Formation Java / Spring Boot – Montée en puissance technique
À l’issue de cette journée, vous serez capable de :
Controller
Service
Repository
@RestController
@GetMapping
@PostMapping
@PathVariable
@RequestBody
Entity
À partir d’aujourd’hui, on construit une vraie application backend.
Pour tester facilement les endpoints, vos URI, vous pouvez intégrer Swagger dans votre application Spring Boot.
endpoints
com.banque ├── BanqueApplication.java ├── controller │ └── CompteController.java ├── service │ └── CompteService.java ├── repository │ └── CompteRepository.java ├── domain (ou model ou entity) │ └── Compte.java │ └── CompteCourant.java │ └── CompteEpargne.java └── exception └── DebitInterditException.java
Cette architecture est :
Tout est automatique, mais pas magique.
@RestController @RequestMapping("/api/comptes") public class CompteController { }
@RestController = @Controller + @ResponseBody
@Controller
@ResponseBody
Les objets retournés sont automatiquement convertis au format JSON.
@GetMapping("/ping") public String ping() { return "Banque API is running..."; }
Test :
http://localhost:8080/api/comptes/ping
@GetMapping("/exemple") public Compte exemple() { return new CompteEpargne("FR001", new BigDecimal("1000")); }
Spring transforme l’objet Java en JSON comme ci-dessous :
{ "numero": "FR001", "solde": 1000 }
Pourquoi en JSON, tout simplement parce que c’est le format (clef -> Valeur) le plus utilisé et le plus facile à exploiter pour la partie Front (VueJS, Angular, React). Nous verrons qu’avec Thymeleaf, on peut s’en passer car il peut manipuler des objets Java.
@RestController @RequestMapping("/api/comptes") public class CompteController { private final CompteService service; public CompteController(CompteService service) { this.service = service; } }
Ici, on fait une Injection par constructeur, c’est-à-dire, on passe le service comme argument dans le constructeur et Spring Boot se charge de l’instancier ! On pourrait aussi le faire en utilisant une simple annotation @Autowired dans la déclaration sans avoir de passer ce service dans comme argument, mais ce n’est plus une bonne pratique et cela rend les tests unitaires difficiles.
Injection par constructeur
@Autowired
@Service public class CompteService { private final CompteRepository repository; public CompteService(CompteRepository repository) { this.repository = repository; } public List<Compte> listerComptes() { return repository.findAll(); } }
Remarquez que nous utilisons le même principe d’injection dans le contrôleur en passant le Repository.
@Repository public class CompteRepository { private final Map<String, Compte> stockage = new HashMap<>(); public List<Compte> findAll() { return new ArrayList<>(stockage.values()); } public void save(Compte compte) { stockage.put(compte.getNumero(), compte); } public Compte findByNumero(String numero) { return stockage.get(numero); } }
Cette implémentation sera remplacée par JPA plus tard et le reste du code ne changera PAS. Souvenez-vous de DAO avec le concepts des Interfaces. C’est exactement la même chose ici.
On ajoute une annotation pour chaque méthode du Controller. L’appel à l’url permettra d’exécuter la méthode qui correspond.
@GetMapping("/api/comptes") public List<Compte> lister() { return service.listerComptes(); }
Testez l’url GET /api/comptes
GET /api/comptes
@PostMapping public void creerCompte(@RequestBody Compte compte) { service.creerCompte(compte); }
Spring :
{ "numero": "FR002", "solde": 500 }
Dans le service, le code métier et donc le nom des méthodes est différent de celles du Repository.
public void creerCompte(Compte compte) { repository.save(compte); }
Lorsque l’on reçoit des paramètres (variables), on les récupère en précisant que ce sont des *variables dans l’url** avec l’annotation @PathVariable.
@GetMapping("/{numero}") public Compte getCompte(@PathVariable String numero) { return service.trouverCompte(numero); }
Nous devons traiter ce problème avec des Exceptions.
public Compte trouverCompte(String numero) { Compte compte = repository.findByNumero(numero); if (compte == null) { throw new IllegalArgumentException("Désolé, compte introuvable !"); } return compte; }
La gestion HTTP fine viendra plus tard avec @ControllerAdvice.
@ControllerAdvice
Consignes :
Objectif : Reprendre du code d’un précédent TP et réorganiser votre code :
/crediter
/debiter
À ce stade :
Vous savez maintenant :
La prochaine fois, on abordera :
On passe de l’API stateless à l’API persistante.