Questions de cours

Modérateurs : graffiop, jmdouin, agoncal, mlebihan

velitc_v
Messages : 64
Inscription : 04 oct. 2019 14:53

Questions de cours

Message par velitc_v » 03 janv. 2020 18:34

Bonjour,
Voici un échange avec M. Rosmorduc sur des questions de cours. En espérant que ça vous aide.
Bon courage et surtout bonne année à tous : Santé, réussite et bonheur en quelques mots.. :)
Virginie

_____________________________
Spring intro
______________________________

Slide 57
Bean prototype à quoi ça sert ?

Le bean « normal » est un bean singleton. Il n’existe qu’en un seul exemplaire, et, quand on demande de l’injecter, c’est cet exemplaire unique qui est fourni.

Avec un bean prototype, un nouvel objet est créé à chaque demande d’injection. Donc si j’injecte un bean prototype dans plusieurs contrôleurs, j’aurai un objet différent à chaque fois.
Si on désire ce comportement (par exemple pour des données en session), l’intérêt du bean prototype par rapport à un bête objet java créé par « new » est que le bean prototype, étant géré par Spring,
bénéficie de l’injection de dépendances. On peut y injecter d’autres beans (par exemple un service).


Slide 63
Bean et Singleton
Quel est la différence entre @Bean et @Component ?

Les deux créent des beans (singletons par défaut).

La différence est juste dans la manière de créer l’objet :

- @Bean annote une méthode d’une classe de configuration. Cette méthode retourne un objet, qui est un bean (nommé comme la méthode).
C’est plus pratique quand le bean appartient à une classe déjà existante, et qu’il suffit de le paramétrer.

- @Component annote une classe. Un bean de cette classe sera automatiquement créé. C’est le plus simple quand le bean créé n’appartient pas à une classe standard, et qu’on doit donc l’implémenter.


______________________________
Cours MVC Slide 27
______________________________
Je n'ai pas compris comment fonctionne model. J'ai compris qu'il était créer automatiquement par Spring mais comment, pourquoi ?

C’est un objet qui sera passé à la vue (essentiellement une map contenant des attributs). Spring sait créer et injecter un modèle.


Exemple avec Model
@Controller
public class MessageController {

@Autowired
MessageRepository messageRepository;

@GetMapping("/list2")
public String getlist2(Model model) {
model.addAttribute("messages", messageRepository.getMessages());
return "liste";
}
}


On peut très bien le créer dans la méthode (je crois que je le fais de temps à autre), mais il faut alors trouver un
moyen de le transmettre à la vue.

C’est pour cela qu’on utilise aussi la classe « ModelAndView » (comme dans l’exemple suivant).

L’avantage avec l’injection de Model est que ma méthode peut retourner simplement le nom de la vue, et que le modèle est créé par ailleurs et injecté comme argument.
On ne l’a pas vu en cours, mais il est possible d’avoir des méthodes qui pré-remplissent le modèle avant le traitement des requêtes (annotation ModelAttribute). C’est utile par exemple dans un formulaire où une liste de données à choisir doit être remplie pour initialiser une liste déroulante.


Pour le cas suivant vous nous disiez qu'il existe une annotation @NotNull. j'imagine qu'elle permet d'indiquer que, Integer a, ne doit pas être null. Comment l'écrivez-vous, avant la méthode ou dans les paramètres ?

@RequestMapping(value = "/add", method = RequestMethod.GET)
public ModelAndView somme(Integer a, Integer b) {
int somme = a + b;
return new ModelAndView("simpleCalc", "resultat", somme);
}

Avant chaque paramètre : @NotNull Integer a, @NotNull Integer b

______________________________
JPA
______________________________
Comment c'est possible d'avoir un objet détaché et donc à merger ? que dans le cas d'une serialisation ?

Un objet est automatiquement détaché quand la transaction se termine. C’est ce qui arrive par exemple à un objet entité retourné par un service et récupéré par un contrôleur.


Je n'ai pas saisi le rapport entre le N+1 SELECT (qui est causé par un défaut de jointure) et les DTO. Comment les DTO pallient à ce problème ?

Ils ne pallient pas ce problème tout seul. Mais l’idée est la suivante :

Dans le cas de l’affichage de données, le DTO est un objet qui contient les données à afficher.
Ces données sont copiées depuis une (ou plusieurs) entités (des objets tirés de la base de données et gérés par JPA).

Ce qui se produit alors :

1. Le contrôleur demande à un service de lui fournir les DTO correspondant à ce tout ce qu’il veut afficher.
2. le service (qui est transactionnel, on va en parler jeudi) interroge la base, récupère des entités, et en recopie les données dans des DTO.
3. il les renvoie au contrôleur, qui a alors toutes les données qu’il veut afficher. Plus besoin de faire appel à la base de données pour cet affichage-là.

Quelque exemples :

A. Si un contrôleur veut afficher les dates et les numéros des factures, il peut les demander à un service, qui lui renverra des DTO
ne contenant que cette information.
B. Si un contrôleur veut afficher le contenu des factures, il peut demander à un service des DTO contentant essentiellement l’intégralité des informations
des factures (y compris les lignes des factures).


C’est le cas B. qui est intéressant pour comprendre le N+1 select.

Supposons que le service retourne directement les entités (objets @Entity) et non des DTO. Plusieurs cas sont alors possibles :
- « normalement », on a juste récupéré les objets Facture. Pas leurs lignes. Comme au moment de l’affichage, les objets sont détachés (l’interaction avec la BD est terminée),
le code va planter car il sera incapable d’afficher les informations liées aux lignes.
- si on a, dans la requête faite à la BD, effectué un LEFT JOIN FETCH pour les données qu’on veut afficher, nos @Entities sont correctement remplies et s’afficheront bien
(et on n’aura pas non plus de N+1 select). Mais notre code est un peu fragile : si les objets se complexifient, on risque de retomber sur le premier cas
- dernière possibilité sans DTO : on utilise « open session in view », qui permet de se reconnecter à la base de données à la demande. Mais là, c’est en gros une quasi garantie qu’on fait du N+1 select

Les DTO ne protègent pas directement du N+1 Select. Mais comme elles encouragent à récupérer précisément les données qu’on veut afficher, elles incitent à écrire les requêtes en conséquence.




Si j'ai bien compris en SpringBoot pas de DTO que des repository donc pas de problème...

Vous confondez DTO et DAO. Et si, le N+1 select est un problème embêtant en Spring.


Je m'y perds un peu dans l'architecture... Je vais essayer de me faire un schéma... DTO est un pojo du model. Vue que model et DTO sont presque identique, on a envie de factoriser. Utiliser que le model ou faire > une classe abstraite s'il faut absolument avoir deux classes... En tout cas, on a envie que le DTO soit fait de façon transparente…

C’est vrai, et c’est bien le problème. Entre les @Entity et les DTO, la frontière est parfois (souvent) mince. Il n’y a malheureusement pas de bonne solution. Ou on confond les deux,
et on perd l’isolement de la couche métier, avec en prime des problèmes de N+1 select, ou on les sépare, et on duplique du code (simple, mais du code quand même).

Spring permet aussi (on ne l’a pas vu) de créer des repositories qui retournent directement des DTO (qui peuvent même être définis par des interfaces).

Et pour les form vous disiez qu'idéalement il faut faire des classes dédiés c'est bien ça ? du coup, ça fait des model et des DTO encore en plus ? je m'y perds

Oui.
Mais il n’y a pas de duplication pour le « Model » (au sens spring MVC). La classe dédiée est justement ce qu’on stocke dans le Model.


Pour le fichier application.properties, en terme de sécurité, mieux vaut le mettre en dehors de l'appli et la faire pointer dessus ?

En fait, vous pouvez avoir un application.properties interne, avec des valeurs par défaut, et en créer un, externe, pour lancer l’application en production, avec les
valeurs sensibles (mots de passe, etc).


______________________________
Security
______________________________
Slide 38 BuilderUser. je n'ai pas compris comment ça s'utilise/ ça s'articule

Voir aussi slide 37 pour le contexte.

En gros : on utilise ici inMemoryAuthentication, qui n’est vraiment intéressant que pour des tests ou des prototypes, rarement pour des applications terminées.
Ce système gère des utilisateurs définis par le programme. le code du transparent 38 ajoute à ce gestionnaire d’authentification un utilisateur « admin », de mot de passe « admin », ayant les rôles « ADMIN » et « USER ».

Dans le transparent 37, on définit ainsi deux utilisateurs. inMemoryAuthentication utilise un interface « fluide ». Une fois qu’on a commencé à décrire un utilisateur, on va rajouter des informations sur celui-ci ; l’appel de la méthode and() permet de dire « on en a fini avec cet utilisateur, passons au suivant ».

______________________________
JPA AVANCE
______________________________
vidéo finissant par 52-45 (le premier exemple sur les facture et @EntityGraph):
1. je ne suis pas sûr de comprendre pourquoi ça plante. c'est parce que Thymeleaf appel des lignes de factures qui n'ont pas été chargées, c'est bien ça ? et elle n'ont pas été chargées car :
1. jpa.open-in-view = false
2. qu'il n'y a pas de @EntityGraph
3. pas de LEFT JOIN FETCH
Et donc dans ce cas le mode par défaut est lazy. c'est bien ça ?

Oui.

2. quand vous dites qu'il faudrait des DTO ou plutôt des models qui reflètent l'affichage. Vous proposez de choisir une autre architecture ? si c'est selon l'affichage ça ferait bcp de possibilités de class!!

On limitera le problème en se contentant typiquement de quelques « niveaux » de DTO. Par exemple, pour les factures, « simple » et « complète ».

Le mapping héritage Slide 21-26
Comment on gère les séquences d'id communs à tous et les id dans les classes java ? on en met que dans les classes mère et ça en met automatiquement dans les classes filles et en Base de données ?

Une fois les annotations en place, c’est automatique/

Slide 23 pourquoi #authorId est avec un #, c'est une clé étrangère ? ou c'est juste pour indiquer que c'est commun à toutes les tables ?

Oui, c’est une notation pour les clefs étrangères.

Slide 34, c'est bizzare que la clé étrangère soit dans TABLE_DES_MATIERES_ENTREES. Ca fait beaucoup de redondance. Idéalement on aurait voulu :

TABLE_DES_MATIERES ENTREES
TABLE_DES_MATIERES_ID ID_ENTREES_ORDER
. TITRE_OUVRAGE ENTREES
# ENTREES_ORDER_ID


Non : table des matières = une table des matières (parmi d’autres), contenant plusieurs entrées. La clef étrangère est forcément dans l’entrée.
Avec votre représentation, on ne sait plus dans quelle table des matières se trouve une entrée.

Slide 35 comment on note @Embeddable si on remplace Integer par lignesFacture ci dessous? car on ne peux pas préciser ce que c'est.. Spring le reconnait tout seul ? Si j'ai bien compris votre code exemple sur > git même pas besoin de mettre @Embedded sur la map, juste @Embeddable sur LignesFacture.. cool

Dans le transparent, la valeur est un Integer (donc primitif) et la clef est une entité. Rien n’a besoin d’être @Embeddable. Dans le git, la valeur est un objet LigneFacture (plus réaliste), et du coup, il doit être @Embeddable. @Embedded n’est pas nécessaire (remplacé par @ElementCollection)

@ElementCollection
private Map<Produit, LignesFacture> lignesFactures = new HashMap<>();

______________________________
ANNOTATION D'UN TP
______________________________
@Transactional(readOnly=true) l'annotation est pour déclarer une transaction j'imagine. On les a pas vu en cours si je ne me trompe...

Répondre