🖨️ Version PDF
Si on laisse les utilisateurs saisir la race en texte libre :
Berger Australien
berger australien
B. australien
Solution : une table Race (référentiel) + un identifiant court (code).
code
Race 1 ---- * Chien
Traduction :
Client → RaceController → RaceService → RaceRepository → DB
Points pédagogiques :
@Entity
@Id
@Column(nullable=false)
@Entity public class Race { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String code; @Column(nullable = false) private String nom; // getters/setters }
Pourquoi unique=true ?
unique=true
Le repository donne des méthodes :
findAll
save
existsByCode
public interface RaceRepository extends JpaRepository<Race, Long> { boolean existsByCode(String code); }
Pourquoi DTO ?
Dans notre exemple, il n’y a pas d’élément sensible, mais pour d’autres Entités, ça sera le cas.
Attention, il faudra un fichier pour chaque Record
Dans RaceDto :
public record RaceDto(Long id, String code, String nom) {}
Dans RaceCreateDto.java :
public record RaceCreateDto( @NotBlank(message="Le code est obligatoire") @Size(min=2, max=10, message="Le code doit faire 2 à 10 caractères") String code, @NotBlank(message="Le nom est obligatoire") String nom ) {}
Règle : code unique.
Pourquoi ici ?
@Service public class RaceService { private final RaceRepository raceRepository; public RaceService(RaceRepository raceRepository) { this.raceRepository = raceRepository; } public List<RaceDto> list() { return repo.findAll().stream() .map(r -> new RaceDto(r.getId(), r.getCode(), r.getNom())) .toList(); } public RaceDto create(RaceCreateDto dto) { if (raceRepository.existsByCode(dto.code())) { throw new IllegalArgumentException("Le code de race existe déjà : " + dto.code()); } Race r = new Race(); r.setCode(dto.code()); r.setNom(dto.nom()); Race saved = raceRepository.save(r); return new RaceDto(saved.getId(), saved.getCode(), saved.getNom()); } }
Rôle du controller :
@Valid
@RestController @RequestMapping("/api/races") public class RaceController { private final RaceService raceService; public RaceController(RaceService raceService) { this.raceService = raceService; } @GetMapping public List<RaceDto> list() { return raceService.list(); } @PostMapping public ResponseEntity<RaceDto> create(@Valid @RequestBody RaceCreateDto dto) { return ResponseEntity.status(HttpStatus.CREATED).body(raceService.create(dto)); } }
via Swagger ou navigateur :
ou commande (linux) :
curl -X POST http://localhost:8080/api/races \ -H "Content-Type: application/json" \ -d '{"code":"BA","nom":"Berger Australien"}'
On teste la règle code unique.
@ExtendWith(MockitoExtension.class) class RaceServiceTest { @Mock RaceRepository repo; @InjectMocks RaceService service; @Test void should_refuse_duplicate_code() { when(repo.existsByCode("BA")).thenReturn(true); var dto = new RaceCreateDto("BA", "Berger Australien"); assertThrows(IllegalArgumentException.class, () -> service.create(dto)); } }
GET /api/races/{id}