🖨️ Version PDF
Objectif : maîtriser une entité riche, avec relations, auto-références (père/mère), état, et exposition propre via DTO.
Dans Wouaf Wouaf, Chien est au cœur du diagramme :
Chien
C’est une entité parfaite pour aborder tous les aspects du mapping (ORM).
Dans Chien, on trouve :
Et l’enum EtatChien peut contenir contenir : ENREGISTRE, INSCRIT_CONCOURS, EVALUATION, CONFIRME, NON_CONFIRME
EtatChien
ENREGISTRE, INSCRIT_CONCOURS, EVALUATION, CONFIRME, NON_CONFIRME
À retenir : une entité réelle est plus riche qu’un exemple. Dans notre projet j’ai omis certaines informations comme le Pedigree.
Race 1 ---- * Chien Adherent 1 ---- * Chien Chien 0..1 ---- 0..* Chien (pere) Chien 0..1 ---- 0..* Chien (mere)
Traduction :
En base : numeroTatouage doit être unique, sinon, on ne sait plus identifier un chien.
numeroTatouage
Relation réflexive (Auto-référence) = relation vers la même entité.
Piège : boucles JSON si on expose l’entité directement.
Encore une raison d’utiliser DTO pour éviter la boucle infinie !
Le projet a ChienDto :
ChienDto
Ça permet :
ChienMapper (MapStruct) fait la conversion Entity vers DTO.
ChienMapper
Pourquoi c’est bien ?
setXxx
Dans notre contrôleur, on a (sauf si je l’ai déjà modifié) :
@GetMapping("/chiens") public List<Chien> chiens() { return chienRepository.findAll(); }
Pourquoi c’est risqué ?
Refactor attendu : renvoyer List<ChienDto>.
List<ChienDto>
@RestController @RequestMapping("/api/chiens") public class ChienController { private final ChienRepository repo; private final ChienMapper mapper; public ChienController(ChienRepository repo, ChienMapper mapper) { this.repo = repo; this.mapper = mapper; } @GetMapping public List<ChienDto> list() { // ici j'utilise la programmation fonctionnelle pour simplifier et renvoyer une version DTO return repo.findAll().stream().map(mapper::toDto).toList(); } }
raceNom
proprietaireNom
Le projet n’a pas forcément le DTO d’entrée : on le crée.
public record ChienCreateDto( @NotBlank String numeroTatouage, @NotBlank String nom, String endroitMarquage, LocalDate dateNaissance, String couleurRobe, @NotNull Long raceId, @NotNull Long proprietaireId, Long pereId, Long mereId ) {}
But :
Pourquoi un service ?
Pseudo-code :
Avec les Mocks.
@SpringBootTest @AutoConfigureMockMvc class ChienApiTest { @Autowired MockMvc mockMvc; @Test void list_chiens_returns_200() throws Exception { mockMvc.perform(get("/api/chiens")).andExpect(status().isOk()); } }
GET /api/chiens/byTatouage/{num}