En utilisant MySQL:
docker run --name mysql_renault -e MYSQL_ROOT_PASSWORD=12345 -d mysql:latest
docker ps
(copier / coller le port dans application.yml)docker inspect mysql_renault
(copier / coller le port dans application.yml)En utilisant Postgresql
Configurer la bdd dans application.yml avec la bdd choisie. Démarrer le serveur Spring Boot (http://localhost:8008):
# Linux & MacOS
./gradlew bootRun
# Windows
gradlew bootRun
Des tests unitaires vérifie que vos endpoints REST fonctionnent correctement. Pour les exécuter :
# Linux & MacOS
./gradlew test
# Windows
gradlew test
Pour travailler les relations, les transactions, et revoir les contrôleurs, nous allons développer l’application “cities”, qui met en relation des pays, régions, et villes. Des utilisateurs peuvent “follow” des villes :
Le backend est à développer en TDD : chaque test unitaire vérifie le bon fonctionnement des différentes parties. Lors de la journée en commun du mercredi, nous allons ajouter le frontend nécessaire pour appeler le backend.
Language
- ÉchauffementUn énuméré Language
a été créé et sera utile pour les pays plus tard. Créer un REST controlleur avec les URLs suivants:
Vérification :
Part0LanguageTest
Country
- IntroductionCréer une nouvelle entitée Country
avec les propriétés suivantes :
int
) NOT NULL PRIMARY KEYString
) NOT NULLLanguage
) NOT NULLCréer un REST controlleur avec les URLs suivants:
Dans CitiesApplication
, ajouter du contenu au démarrage de l’application :
id | language | name |
---|---|---|
1001 | “FR” | “France” |
1002 | “EN” | “Canada” |
1003 | “JA” | “Japan” |
Region
- Mapping bidirectionnelCréer une nouvelle entitée Region
avec les propriétés suivantes :
int
) NOT NULL PRIMARY KEYString
) NOT NULLCountry
) NOT NULL FOREIGN KEY (see https://www.baeldung.com/hibernate-one-to-many)Dans Country
ajouter les propriétés suivantes (implémentation d’un mapping “bidirectionel”, voir https://docs.oracle.com/cd/E19798-01/821-1841/bnbqj/index.html) :
List<Region>
(see https://www.baeldung.com/hibernate-one-to-many)Créer un REST controlleur avec les URLs suivants :
Puisque la Region
a une clef étrangère qui référence un Country
, vous allez devoir insérer le pays avant, dans une transaction:
java.sql.SQLIntegrityConstraintViolationException: Column 'country_id' cannot be null
@Transactional
https://dzone.com/articles/how-does-spring-transactionalDans CitiesApplication
, ajouter du contenu au démarrage de l’application :
id | name | country_id |
---|---|---|
2001 | “IDF” | 1001 |
2002 | “Québec” | 1002 |
Questions :
@OneToMany(mappedBy = "country", cascade = CascadeType.REMOVE)
?@OneToMany(mappedBy = "country", fetch = FetchType.EAGER)
?@Fetch(value = FetchMode.SELECT)
?City
- Mapping bidirectionnelAjouter les mêmes fonctionnalités que pour région sur un nouvel entité City
.
Dans CitiesApplication
, ajouter du contenu au démarrage de l’application :
id | name | region_id |
---|---|---|
3001 | “Paris” | 2001 |
3002 | “Montreuil” | 2001 |
3003 | “Montréal” | 2002 |
3004 | “Laval” | 2002 |
User
- Association ManyToManyCréer une nouvelle entité User
. Un utilisateur pourra “suivre” une ville (si vous n’avez pas fait la partie 3, un utilisateur pourra suivre une région) :
int
) NOT NULL PRIMARY KEYString
) NOT NULLList<City
) (see https://www.baeldung.com/jpa-many-to-many)Afin d’implémenter followedCity
, il faut créer une table de jointure, nommée “user_city”, qui a 2 colonnes:
int
) PRIMARY KEY FOREIGN KEYint
) PRIMARY KEY FOREIGN KEYCréer un REST controlleur avec les URLs suivants :
Dans CitiesApplication
, ajouter du contenu au démarrage de l’application :
Table “user” :
id | name |
---|---|
4001 | “Alex” |
Table “user_city” :
user_id | city_id |
---|---|
4001 | 3001 |
4001 | 3002 |
@Valid
- ValidationDans cette partie, nous allons valider les entité au niveau des entités et de la bdd.
Pour les entités :
@NotNull
, @Length(min = ..., max = ...)
pour CountryDto
, RegionDto
, CityDto
@Valid
sur les méthodes POST dans CountryController
, RegionController
, CityController
CountryTest
, RegionTest
, CityTest
Country
, Region
, City
!Pour la BDD :
@Column(nullable = ..., length = ...)
pour Country
, Region
, City
spring.jpa.generate-ddl: true
drop table city if exists
drop table country if exists
drop table region if exists
drop table user if exists
create table city (id integer generated by default as identity, name varchar(255), primary key (id))
create table country (id integer generated by default as identity, language varchar(255), name varchar(512) not null, primary key (id))
create table region (id integer generated by default as identity, name varchar(255), country_id integer, primary key (id))
create table user (id integer generated by default as identity, primary key (id))
alter table region add constraint FK7vb2cqcnkr9391hfn72louxkq foreign key (country_id) references country
Dans cette partie, nous allons approfondir certains sujets :
user.getFollowedCities()
, pour tous les users qui suivent cette villeCascadeType
, qui feront des suppressions automatiquesLe test suivant doit passer : ```java public class Part3CityTest extends TestCitiesApplication {
@Test public void should_DELETE_city_should_remove_city_even_if_followed() { int parisId = getCityIdForName(“Paris”).orElseThrow(); delete(format(“country/region/city/%s”, parisId));
List<String> cityNames = getCityNames();
assertEquals(3, cityNames.size());
assertFalse(cityNames.contains("Paris"));
List<String> userNames = getUserNames();
assertEquals(1, userNames.size());
assertTrue(userNames.contains("Alex")); }
} ```
CountryRegionDto
, puis en cascade sur CountryDto
et RegionDto
Le test suivant doit passer : ```java public class Part5ValidationTest extends TestCitiesApplication {
@Test public void should_POST_root_region_name_too_short_validation_fails() { JsonObject badRegionName = Json.createObjectBuilder() .add(“country”, Json.createObjectBuilder() .add(“name”, “United Kingdom”) .add(“language”, “English”) .build()) .add(“region”, Json.createObjectBuilder() .add(“name”, “ff”) .build()) .build(); HttpStatus status = assertThrows(ResponseStatusException.class, () -> post(“country/region”, badRegionName)) .getStatus(); assertEquals(BAD_REQUEST, status);
List<String> countryNames = getCountryNames();
assertEquals(3, countryNames.size());
List<String> regionNames = getRegionNames();
assertEquals(2, regionNames.size()); }
} ```