・ Apprentissage de Java / Spring Boot / Thymeleaf ・ Je souhaite créer une application Web simple pour la pratique
Créez une application Web simple qui vous permet de gérer les clients (inscription / mise à jour / suppression / liste). La certification / l'autorisation / le test unitaire est omis car ce sera beaucoup. Cependant, il peut être préférable d'ajouter le test unitaire s'il reste du temps.
L'image terminée est la suivante.
Si vous souhaitez d'abord voir le produit fini, veuillez.
La source est ici.
Celui qui fonctionne est ici.
On suppose que l'environnement de développement et PostgreSQL ont été installés. Si vous ne l'avez pas installé, veuillez suivre le lien ci-dessous.
La configuration globale de l'application Web créée cette fois est la suivante.
Grosso modo ...
Le développement étant le thème principal, la conception fonctionnelle est facile à écrire.
No | Nom de l'écran | La description |
---|---|---|
1 | l'écran supérieur | L'écran qui sert d'entrée à chaque écran. |
2 | Nouvel écran d'inscription | Un écran pour les informations client nouvellement enregistrées. |
3 | Écran de mise à jour | Un écran pour modifier les informations client. |
4 | Écran de liste | Un écran pour afficher et supprimer des informations client dans une liste. |
Conformément à [2. Objectif](# 2-Objectif).
Je pense que vous pouvez le comprendre, alors je l'ai omis.
No | URL | Méthode HTTP | La description |
---|---|---|---|
1 | / | GET | l'écran supérieur |
2 | /customers | GET | Écran de liste |
3 | /customers/create | GET | Nouvel écran d'inscription |
4 | /customers/create | POST | Nouvelle exécution d'enregistrement |
5 | /customers/{id}/update | GET | Écran de mise à jour |
6 | /customers/{id}/update | POST | Exécution de la mise à jour |
7 | /customers/{id}/delete | GET | Supprimer l'exécution |
Conçu en référence à ici.
No | nom de la table | La description |
---|---|---|
1 | customer | Gérez les informations client. |
No | Nom de colonne | PK | Non nul | La description |
---|---|---|---|---|
1 | id | ○ | ○ | N ° de client. Numérotation automatique en séquence. |
2 | name | ○ | Nom du client. |
Passons maintenant au développement du sujet principal.
Téléchargez le modèle sur le site officiel de Spring et développez-le. La table est automatiquement générée à partir du modèle par la fonction de Spring JPA.
Créez un modèle pour votre projet d'application Web. Il est facile à télécharger depuis Spring Initializr. Vous pouvez le télécharger en entrant ce qui suit et en appuyant sur le bouton "Générer".
Définissez les bibliothèques externes à utiliser.
Vous pouvez faire de même à partir du menu Eclipse. Plus précisément, il s'agit de "Fichier", "Nouveau", "Autre", "Spring Boot" et "Spring Starter Project".
Importez le modèle téléchargé dans Eclipse. La procédure spécifique est la suivante.
Il sera construit automatiquement lors de l'importation, selon les dépendances dans build.gradle, Les bibliothèques externes seront téléchargées.
Certaines bibliothèques externes ne sont pas incluses dans Spring Initializr. Plus précisément, la bibliothèque java bootstrap n'est pas incluse. Ouvrez le fichier build.gradle dans Eclipse et ajoutez comme suit.
build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.webjars:jquery:3.3.1' //ajouter à
implementation 'org.webjars:bootstrap:4.3.1' //ajouter à
implementation 'org.webjars:font-awesome:5.13.0' //ajouter à
//réduction. La version complète est https://github.com/tk230to/tksystem
Recherchez ces bibliothèques dans le référentiel Maven (https://mvnrepository.com/).
Créez chaque classe et fichier de configuration.
Créez un fichier de modèle / vue / contrôleur / configuration. Quel était ce fichier? Dans ce cas, veuillez relire [5.2 Configuration](# 52-Configuration).
Créez une classe correspondant à la table client (conception # 63-db). Nom de classe = nom de table, nom de champ = nom de colonne.
Customer.java
package com.example.tksystem.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.NotBlank;
import lombok.Data;
/**
*Classe de client.
*/
@Entity
@Data
public class Customer {
/**Nom de la séquence*/
private static final String SEQUENCE_NAME = "customer_id_seq";
/** ID */
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE_NAME)
@SequenceGenerator(name = SEQUENCE_NAME, sequenceName = SEQUENCE_NAME, allocationSize = 1)
private Long id;
/**Nom*/
@NotBlank
private String name;
}
Créez une classe pour effectuer des opérations CRUD sur la table client. Il hérite simplement de JpaRepository.
CustomerRepository.java
package com.example.tksystem.model;
import org.springframework.data.jpa.repository.JpaRepository;
/**
*Classe de référentiel client.
*/
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
Les méthodes (extraits) suivantes seront disponibles.
Créez un modèle HTML pour chaque écran. Comme la barre de navigation en haut est commune à tous les écrans, elle sera partagée en tant que mise en page commune.
layout.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="head(title)">
<title th:text="'Gestion de la clientèle- ' + ${title}">tksystem</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.min.css}" />
<link rel="stylesheet" th:href="@{/webjars/font-awesome/5.13.0/css/all.min.css}" />
<script th:src="@{/webjars/jquery/3.3.1/jquery.min.js}"></script>
<script th:src="@{/webjars/bootstrap/4.3.1/js/bootstrap.min.js}"></script>
</head>
<body>
<nav class="navbar navbar-dark bg-dark navbar-expand-sm mb-3" th:fragment="navbar">
<a class="navbar-brand" href="/">Gestion de la clientèle</a>
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#Navbar" aria-controls="Navbar" aria-expanded="false" aria-label="Changement de navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div id="Navbar" class="collapse navbar-collapse">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" th:href="@{/customers/create/}">
<i class="fas fa-plus fa-lg" aria-hidden=”true”></i>s'inscrire
</a>
</li>
<li class="nav-item">
<a class="nav-link" th:href="@{/customers/}">
<i class="fas fa-list fa-lg" aria-hidden=”true”></i>liste
</a>
</li>
</ul>
</div>
</nav>
</body>
</html>
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/layout :: head('Home')">
</head>
<body>
<div th:replace="fragments/layout :: navbar"></div>
<div class="container-fluid">
<h5>menu</h5>
<hr>
<div class="row">
<div class="col-sm-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">
<a class="nav-link" th:href="@{/customers/create}">
<i class="fas fa-plus fa-lg" aria-hidden=”true”></i>s'inscrire
</a>
</h5>
<p class="card-text">Enregistrez un nouveau client.</p>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">
<a class="nav-link" th:href="@{/customers/}">
<i class="fas fa-list fa-lg" aria-hidden=”true”></i>liste
</a>
</h5>
<p class="card-text">Affichez une liste de clients.</p>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
create.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/layout :: head('s'inscrire')">
</head>
<body>
<div th:replace="fragments/layout :: navbar"></div>
<div class="container-fluid">
<h5>s'inscrire</h5>
<hr>
<div class="row">
<div class="col-sm-12">
<form action="#" th:action="@{/customers/create/}" th:object="${customer}" method="post">
<div class="form-group">
<label for="name">Nom<span class="badge badge-danger">Obligatoire</span></label>
<input type="text" id="name" class="form-control" placeholder="(Exemple)Yamada Taro" th:field="*{name}" />
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" style="color: red"></span>
</div>
<button type="submit" class="btn btn-primary">Confirmer</button>
</form>
</div>
</div>
</div>
</body>
</html>
C'est presque le même que l'écran d'enregistrement. Le produit fini est ici
list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/layout :: head('liste')">
</head>
<body>
<div th:replace="fragments/layout :: navbar"></div>
<div class="container-fluid">
<h5>liste</h5>
<hr>
<div class="row">
<div class="col-sm-12">
<table class="table table-bordered table-hover">
<thead class="thead-dark">
<tr>
<th width="10%">ID</th>
<th width="80%">Nom</th>
<th width="10%">Effacer</th>
</tr>
</thead>
<tbody>
<tr th:each="customer:${customer}">
<td th:text="${customer.id}"></td>
<td>
<a th:text="${customer.name}" th:href="@{/customers/{id}/update/(id=${customer.id})}">
</a>
</td>
<td>
<a th:href="@{/customers/{id}/delete/(id=${customer.id})}" onClick="return window.confirm('Etes-vous sûr que vous voulez supprimer?')">
<i class="far fa-trash-alt fa-lg" aria-hidden=”true”></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
Créez une classe pour gérer les demandes d'écran supérieur.
IndexController.java
package com.example.tksystem.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
*classe de contrôleur d'écran d'index.
*/
@Controller
@RequestMapping("/")
public class IndexController {
/**
*écran d'index
*
* @modèle de modèle param
* @retour Destination de transition
*/
@RequestMapping("index")
public String index(Model model) {
return "index";
}
}
Créez une classe pour traiter les demandes sur l'écran client (nouvel écran d'inscription / mise à jour / liste).
CustomerController.java
package com.example.tksystem.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.tksystem.model.Customer;
import com.example.tksystem.model.CustomerRepository;
/**
*Classe de contrôleur d'écran client.
*/
@Controller
@RequestMapping("/customers")
public class CustomerController {
/**enregistrement/mise à jour/Rediriger l'URL de destination une fois la suppression terminée*/
private static final String REDIRECT_URL = "redirect:/customers/";
/**Chemin HTML*/
private static final String PATH_LIST = "customer/list";
private static final String PATH_CREATE = "customer/create";
private static final String PATH_UPDATE = "customer/update";
/**Nom d'attribut du modèle*/
private static final String MODEL_ATTRIBUTE_NAME = "customer";
/**Référentiel client*/
@Autowired
private CustomerRepository customerRepository;
/**
*Affichez l'écran de liste.
*
* @modèle de modèle param
* @retour Destination de transition
*/
@GetMapping(value = "/")
public String list(Model model) {
model.addAttribute(MODEL_ATTRIBUTE_NAME, customerRepository.findAll(Sort.by("id")));
return PATH_LIST;
}
/**
*Affichez l'écran d'enregistrement.
*
* @modèle de modèle param
* @retour Destination de transition
*/
@GetMapping(value = "/create")
public String create(Model model) {
model.addAttribute(MODEL_ATTRIBUTE_NAME, new Customer());
return PATH_CREATE;
}
/**
*Effectuez l'enregistrement.
*
* @Param client Valeur d'entrée de l'écran client
* @résultat du paramètre Résultat du contrôle d'entrée
* @retour Destination de transition
*/
@PostMapping(value = "/create")
public String create(@Validated @ModelAttribute(MODEL_ATTRIBUTE_NAME) Customer customer,
BindingResult result) {
if (result.hasErrors()) {
return PATH_CREATE;
}
customerRepository.save(customer);
return REDIRECT_URL;
}
/**
*Affichez l'écran de mise à jour.
*
* @ID de paramètre ID client
* @modèle de modèle param
* @retour Destination de transition
*/
@GetMapping(value = "/{id}/update")
public String update(@PathVariable("id") Long id, Model model) {
model.addAttribute(MODEL_ATTRIBUTE_NAME, customerRepository.getOne(id));
return PATH_UPDATE;
}
/**
*Effectuez la mise à jour.
*
* @Param client Valeur d'entrée de l'écran client
* @résultat du paramètre Résultat du contrôle d'entrée
* @retour Destination de transition
*/
@PostMapping(value = "/{id}/update")
public String update(@Validated @ModelAttribute(MODEL_ATTRIBUTE_NAME) Customer customer,
BindingResult result) {
if (result.hasErrors()) {
return PATH_UPDATE;
}
customerRepository.save(customer);
return REDIRECT_URL;
}
/**
*Effectuer la suppression.
*
* @ID de paramètre ID client
* @retour Destination de transition
*/
@GetMapping(value = "/{id}/delete")
public String list(@PathVariable("id") Long id) {
customerRepository.deleteById(id);
return REDIRECT_URL;
}
}
application.yml Ce fichier est utilisé pour définir les informations de connexion à la base de données, etc. url / nom d'utilisateur / mot de passe est la valeur par défaut pour PostgreSQL. S'il est différent de la valeur par défaut, modifiez-le.
application.yml
spring:
datasource:
#Adresse IP Postgres/numéro de port/Nom de la base de données
url: jdbc:postgresql://localhost:5432/postgres
#Nom d'utilisateur Postgres
username: postgres
#Mot de passe Postgres
password: postgres
#Pilote JDBC Postgres
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
# @Déposez toujours la table correspondant à l'entité&créer.
ddl-auto: create-drop
hibernate.properties Ce paramètre évite les exceptions qui se produisent dans PostgreSQL x Spring JPA. Il n'y a pas de problème de fonctionnement sans elle, mais il est désagréable d'obtenir une exception à chaque fois, il est donc préférable de la définir. Détails de l'exception ici
hibernate.properties
# PgConnection.createClob()Évitez les avertissements de méthode
hibernate.jdbc.lob.non_contextual_creation = true
ValidationMessages.properties La définition du message du message d'erreur de vérification d'entrée. Je vais créer le mien car le message japonais n'a pas encore été fourni. La demande d'extraction a été capturée à ici, donc je pense qu'elle sera fournie bientôt.
ValidationMessages.properties
javax.validation.constraints.AssertFalse.message =Veuillez définir sur false
javax.validation.constraints.AssertTrue.message =Veuillez définir sur true
javax.validation.constraints.DecimalMax.message = {value} ${inclusive == true ? 'Veuillez définir les valeurs suivantes' : 'Veuillez le réduire'}
javax.validation.constraints.DecimalMin.message = {value} ${inclusive == true ? 'Veuillez définir la valeur ci-dessus' : 'Veuillez définir une valeur plus élevée'}
javax.validation.constraints.Digits.message =La valeur doit être dans la plage suivante(<entier{integer}chiffre>.<Après la virgule décimale{fraction}chiffre>)
javax.validation.constraints.Email.message =Veuillez le formater correctement comme adresse e-mail
javax.validation.constraints.Future.message =Veuillez définir une date ultérieure
javax.validation.constraints.FutureOrPresent.message =Définir la date actuelle ou future
javax.validation.constraints.Max.message = {value}Veuillez définir les valeurs suivantes
javax.validation.constraints.Min.message = {value}Veuillez définir la valeur ci-dessus
javax.validation.constraints.Negative.message =Doit être inférieur à 0
javax.validation.constraints.NegativeOrZero.message =Veuillez définir la valeur sur 0 ou moins
javax.validation.constraints.NotBlank.message =Les blancs ne sont pas autorisés
javax.validation.constraints.NotEmpty.message =Les éléments vides ne sont pas autorisés
javax.validation.constraints.NotNull.message =null n'est pas autorisé
javax.validation.constraints.Null.message =Veuillez le rendre nul
javax.validation.constraints.Past.message =Veuillez définir une date antérieure
javax.validation.constraints.PastOrPresent.message =Veuillez régler la date actuelle ou passée
javax.validation.constraints.Pattern.message =Expressions régulières"{regexp}"Veuillez correspondre à
javax.validation.constraints.Positive.message =Doit être supérieur à 0
javax.validation.constraints.PositiveOrZero.message =Doit être supérieur ou égal à 0
javax.validation.constraints.Size.message = {min}De{max}Veuillez faire la taille entre
WebConfig Définissez les paramètres pour utiliser les ValidationMessages.properties ci-dessus. Veuillez consulter ici pour plus de détails.
WebConfig.java
package com.example.tksystem;
import java.nio.charset.StandardCharsets;
import org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
*Classe de configuration Web.
*
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public Validator getValidator() {
// ValidationMessages.Propriétés à UTF-Vous permet de définir avec 8.
ReloadableResourceBundleMessageSource messageSource =
new ReloadableResourceBundleMessageSource();
messageSource.setBasename(AbstractMessageInterpolator.USER_VALIDATION_MESSAGES);
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource);
return validator;
}
}
Maintenant que tous les fichiers sont complets, exécutez le projet dans Eclipse. La procédure consiste à sélectionner un projet, à cliquer avec le bouton droit de la souris, à exécuter et à appliquer Spring Boot.
En définissant ddl-auto set dans application.yml La table est automatiquement générée en fonction de la classe Entity créée.
Accédez à [http: // localhost: 8080](http: // localhost: 8080) et vérifiez le fonctionnement. Si cela fonctionne comme [2. Objectif](# 2-Objectif), il réussit.
Je vous remercie pour votre travail acharné.
Recommended Posts