spring framework - e-monsitelecurseur.e-monsite.com/.../seance3-spring-framework.pdf ·...
TRANSCRIPT
Spring framework
Les conteneurs IoC
Le conteneur Spring utilise DI pour gérer les composants qui constituent une
application.
Le diagramme suivant montre une
vue de haut niveau du fonctionnement
de Spring. Vos classes d'application
sont combinées avec des
métadonnées de configuration afin
qu'après la création et l'initialisation
d'ApplicationContext, vous disposiez
d'un système ou d'une application
entièrement configuré
Spring framework
Les conteneurs IoC
Il existe deux types de conteneurs IoC :
BeanFactory : Interface qui existe dans le package
org.springframework.beans.factory.BeanFactory
ApplicationContext : Interface qui existe dans le package
org.springframework.context.ApplicationContext
L’interface ApplicationContext est construite au-dessus de l’interface BeanFactory. Il
ajoute quelques fonctionnalités supplémentaires que BeanFactory tels que l’intégration
simple avec l’AOP de Spring, la couche application contexte spécifique (par exemple
WebApplicationContext) pour les applications Web. Il est donc préférable d’utiliser
ApplicationContext que BeanFactory.
Spring framework
L’injection de dépendances
L’injection de dépendance(DI) est un design pattern qui nous permet de
supprimer les dépendances entre les objets et de faire l’injection
automatiquement lors du démarrage du conteneur Spring.
Les informations seront fournies depuis un fichier xml.
Nous avons deux façons pour faire l’injection de dépendance :
• Par Constructeur.
• Par la méthode setter.
Spring framework
L’injection de dépendances
Nous allons créer une classe Personne.java qui va contenir 2 variables (id
et nom), trois constructeurs et une méthode, ci-dessous le code source.
Injecter une variable Primitive :
package univ.fac.master;
public class Personne {private int id;private String nom;
public Personne(int id) {this.id = id;}public Personne(String nom) { this.nom = nom;}public Personne(int id, String nom) {
this.id = id;this.nom = nom;
}void afficher(){ System.out.println(id+" "+nom); }}
Spring framework
L’injection de dépendances
Nous allons maintenant créer le fichier applicationContexte.xml, c’est au
niveau de ce fichier que nos objets seront créés ainsi que leur injection.
Injecter une variable Primitive :
<?xml version="1.0" encoding="UTF-8"?><beans
xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><!—Si on veut injecter une seule variable de type Int (on va appeler le constructeur
qui a un seul paramètre) --><bean id="per" class="univ.fac.master.Personne"><constructor-arg value="25" type="int"></constructor-arg></bean>
Spring framework
L’injection de dépendances
Nous allons maintenant créer le fichier applicationContexte.xml, c’est au
niveau de ce fichier que nos objets seront créés ainsi que leur injection.
Injecter une variable Primitive :
<!—Si on veut injecter une seule variable de type String (on va appeler le constructeur qui a un seul paramètre) <bean id="per" class="univ.fac.master.Personne"><constructor-arg value="Karim" type="String"></constructor-arg></bean><!—Si on veut injecter une seule variable de type String (on va appeler le constructeur qui a
un seul paramètre) --><bean id="per" class="univ.fac.master.Personne"><constructor-arg value="25" type="int"></constructor-arg><constructor-arg value="Karim"></constructor-arg></bean></beans>
<bean id="per" class="univ.fac.master.Personne"><property name="id"><value>10</value></property><property name="nom"><value>Kamal</value></property>
</bean>
Par constructeur
Par setter
Spring framework
L’injection de dépendances
Créer la classe principale
Injecter une variable Primitive :
package univ.fac.master;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");Personne p = context.getBean("per",Personne.class);p.afficher();}}
Spring framework
L’injection de dépendances
Modifions la classe Personne pour qu’elle comporte un objet adresse
Injecter un Objet :
public class Personne {private int id;private String nom;private Adresse adresse;// une relation de type agrégation
public Personne(int id, String nom, Adresse adresse) {this.id = id;this.nom = nom;this.adresse = adresse;
}void afficher(){
System.out.println(id+" "+nom);System.out.println(adresse.afficher());
}//getters et setters}
Spring framework
L’injection de dépendances
Injecter un Objet :
<bean id="per" class="univ.fac.master.Personne"><constructor-arg value="25" type="int"></constructor-arg></bean>
<bean id="per" class="univ.fac.master.Personne"><constructor-arg value="Kamal" type="String"></constructor-arg></bean>
<bean id="adresse" class="univ.fac.master.Addresse"><constructor-arg value="Ville"></constructor-arg><constructor-arg value="Pays"></constructor-arg></bean>
<bean id="per" class="univ.fac.master.Personne"><constructor-arg value="25" type="int"></constructor-arg><constructor-arg value="Kamal"></constructor-arg><constructor-arg> <ref bean="adresse"/> </constructor-arg></bean>
<bean id="adr" class="univ.fac.master.Adresse"><property name="adresse" value="Adresse1"></property></bean><bean id="per" class="univ.fac.master.Adresse"><property name="id" value="1"></property><property name="nom" value="Kamal"></property><property name="adresse" ref="adr"></property></bean>
Par setter
Par constructeur
Spring framework
L’injection de dépendances
Injecter une collection :
public class Personne{private int id;private String nom;private List<String> telephones;
public Personne() {}public Personne(int id, String nom, List<String> telephones) {
this.id = id; this.nom = nom; this.telephones = telephones;}void afficher(){
System.out.println(id+" "+nom); System.out.println("Liste des téléphones: ");Iterator<String> itr= telephones.iterator();while(itr.hasNext()){ System.out.println(itr.next()); }
}
Nous pouvons injecter des valeurs de collections en utilisant un constructeur, trois
éléments peuvent être utilisés dans le tag <constructeur-arg> : List, Set, Map.
Spring framework
L’injection de dépendances
Injecter une collection :
<bean id="C" class="univ.fac.master.Personne"><constructor-arg value="10"></constructor-arg><constructor-arg value="Kamal"></constructor-arg><constructor-arg><list><value>0602987654</value><value>0701998877</value><value>0811223344</value></list></constructor-arg></bean>
<bean id="per" class="univ.fac.master.Adresse"><property name="id" value="1"></property><property name="nom" value="Kamal"></property><property name="telephones">
<list><value>0602987654</value><value>0701998877</value><value>0811223344</value></list>
</property></bean>
Par setter
Par constructeur
Spring framework
L’injection de dépendances
L’annotation @Autowired
C’est une annotation qui nous permet de faire l’injection de dépendances entre les beans
de l’application (Spring va tout faire), il suffit juste d’annoter un constructeur ou une
méthode avec cette dernière. et le conteneur Spring va faire la suite(La création du bean,
le chercher et l’injecter automatiquement…).
Exemplepublic interface IDao{
}
@Repositorypublic class Dao implemets IDao {// Ajouter du code}
@Servicepublic class Metier{@Autowiredprivate IDao dao;}
une fois le conteneur Spring se lance, il va crée l’instance de la classe Dao et la classe
Métier, et il va faire l’injection de dépendance (injecter l’objet créé de la classe Dao dans
la propriété de l’interface IDao qui existe dans la classe Métier)
@Autowired(required=false): pour que l’initialisation des beans ne soit pas obligatoire
Spring framework
L’injection de dépendances
L’annotation @Qualifier
C’est une annotation utilisée lorsqu’on a plusieurs classes qui implémentent une interface,
et on veux faire l’injection des dépendances en utilisant cet interface.
Dans une seule application , on a une
interface IDao qui sera implémentée
par 3 classes : DaoJdbc, DaoHibernate,
DaoSpringData.
Exemple
public interface IDao {
}
@Repository@Qualifier("jdbc")public class DaoJdbc implemets IDao {// Ajouter du code}@Qualifier("hibernate")public class DaoJdbc implemets IDao {// Ajouter du code}@Qualifier("springData")public class DaoJdbc implemets IDao {// Ajouter du code}
public class Metier {@Autowired@Qualifier("jdbc")private IDao dao;}
Spring framework
L’injection de dépendances
L’annotation @Resource
Elle s’agit d’une fusion entre l’annotation @Autowired et @Qualifier
ExempleDans une seule application , on a une
interface IDao qui sera implémentée
par 3 classes : DaoJdbc, DaoHibernate,
DaoSpringData.
public interface IDao {
}
@Repository@Qualifier("jdbc")public class DaoJdbc implemets IDao {// Ajouter du code}@Qualifier("hibernate")public class DaoJdbc implemets IDao {// Ajouter du code}@Qualifier("springData")public class DaoJdbc implemets IDao {// Ajouter du code}
public class Metier {@Resource("jdbc")private IDao dao;}
Spring framework
Spring Data
Hibernate vs Spring Data
Hibernate est une implémentation JPA, tandis que Spring Data JPA est
une abstraction d'accès aux données JPA.
Avec Spring Data, vous pouvez utiliser Hibernate, Eclipse Link ou tout
autre fournisseur JPA.
Spring Data JPA n'est pas une implémentation ou un fournisseur JPA,
c'est simplement une abstraction qui consiste à réduire
considérablement la quantité de code requise pour mettre en œuvre les
couches d'accès aux données. Hibernate fournit une implémentation de
référence de l'API Java Persistence
Spring framework
Spring Data
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency>
Créer un nouveau projet « SpringDataProject », et ajouter les starters jpa,
mysql et web
Spring framework
Spring Data
Créer l’arborescence du projets suivante:
Spring framework
Spring Data
Configurer l’accès à la base de données MySQL dans le fichier
« application.properties »
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/base?serverTimezone=UTCspring.datasource.username=rootspring.datasource.password=1234
spring.jpa.show-sql=truespring.jpa.hibernate.ddl-auto=updatespring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
Spring framework
Spring Data
La classe Person@Entitypublic class Person {@Id@ColumnLong id;@ColumnString nom;@ColumnString email;public Person(long id, String nom, String email) {super();this.id = id;this.nom = nom;this.email = email;}public Person() {super();}//setters and getters}
Spring framework
Spring Data
Créer ensuite l’interface PersonRepository
package univ.fac.master.dao;
import org.springframework.data.jpa.repository.JpaRepository;import univ.fac.master.beans.Person;
public interface PersonRepository extends JpaRepository<Person, Long>{
}
L'interface PersonRepository étend (extends) cette interface
JpaRepository<Person, Long>. Il possède des méthodes pour
manipuler les entités. Spring Data JPA créer automatiquement une
classe qui implémente (implements) cette interface en même temps de
l'exécution de l'application.
Spring framework
Spring Data
Créer ensuite l’interface PersonRepository
package univ.fac.master.dao;
import org.springframework.data.jpa.repository.JpaRepository;import univ.fac.master.beans.Person;
public interface PersonRepository extends JpaRepository<Person, Long>{
}
CrudRepository: Juste les fonctionnalités de base de CRUD
PagingAndSortingRepository: Méthodes pour la pagination et le tri
JpaRepository: on a en plus les méthodes propre à JPA
Spring framework
Spring Data
Créer maintenant le contrôleur
@RestControllerpublic class PersonController {@AutowiredPersonRepository personrepository;@GetMapping("/persons")public List<Person> get() {return personrepository.findAll();}@PostMapping("/persons")public void add(@RequestBody Person p) {personrepository.save(p);}}
Compléter le contrôleur afin de
réaliser les opération CRUD qui
restent, puis tester l’application
Spring framework
Spring Data
Repository
CrudRepository
PagingAndSortingRepository
JpaRepository
Pas de méthodes
save(S); findOne(Id); exists(); findAll(); deleteAll();…
findAll(Sort); findAll(Pageable)
flush(); saveAndFlush(T); deleteInBash(Iterable<T>; …)
Spring framework
Spring Data
Génération de requêtes par méthodes
@Entitypublic class Person {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)Long id;@ColumnString name;@Columnint age;@ManyToOne(cascade = CascadeType.ALL, optional = false)@JoinColumn(name = "idR",nullable = false)Room room;...}
Créer la classe « Person »
Spring framework
Spring Data
Génération de requêtes par méthodes
@Entitypublic class Room {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)Long idR;@Column@NotNullString name;...}
Créer la classe « Room »
Spring framework
Spring Data
Génération de requêtes par méthodes
Spring Data JPA dispose d’un ensembles de mots clés pour générer les
requêtes. Par exemple:
public interface PersonRepository extends JpaRepository<Person, Long>{List<Person> findByNameAndAgeLessThan(String name,int age);List<Person> findByNameIgnoreCase(String name);List<Person> findByNameOrderByAgeDesc(String name);List<Person> findByRoom(Room room);List<Person> findDistinctByRoomName(String name);List<Person> findByNameLike(String name);}
Spring framework
Spring Data
Mots-clés pris en charge dans les noms de méthodesKeyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is, Equals findByFirstname,findByFirstnameIs,f
indByFirstnameEquals
… where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull, Null findByAge(Is)Null … where x.age is null
IsNotNull, NotNull findByAge(Is)NotNull … where x.age not null
Spring framework
Spring Data
Mots-clés pris en charge dans les noms de méthodesKeyword Sample JPQL snippet
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age>
ages)
… where x.age in ?1
NotIn findByAgeNotIn(Collection<Age
> ages)
… where x.age not in ?1
Spring framework
Spring Data
Mots-clés pris en charge dans les noms de méthodesKeyword Sample JPQL snippet
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)
Spring framework
Spring Data
Règles pour la création de méthodes de requête
Nous pouvons créer des méthodes de requête qui utilisent cette stratégie en
suivant ces règles:
Le nom de notre méthode de requête doit commencer par l’un des préfixes
suivants: find… By, read… By, query… By, count… By, et get… By.
Si nous voulons limiter le nombre de résultats de requête renvoyés, nous pouvons
ajouter le mot clé First ou le mot clé Top avant le premier mot By . Si nous voulons
obtenir plusieurs résultats, nous devons ajouter la valeur numérique facultative aux
mots-clés Premier et Haut. Par exemple, findTopBy, findTop1By, findFirstBy et
findFirst1By retournent tous la première entité qui correspond aux critères de
recherche spécifiés.
Si nous voulons sélectionner des résultats uniques, nous devons ajouter le mot clé
Distinct avant le premier mot By.
Spring framework
Spring Data
Les requêtes nomméesNous pouvons déclarer des requêtes nommée comme montre l’exemple
suivant:@Entity@NamedQuery(name="Person.findById", query = "select u from Person u where u.id=?1")public class Person{@Id@GeneratedValue(strategy = GenerationType.IDENTITY)Long id;@Column(name="name")String name;@Columnint age;@ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL,optional = false)@JoinColumn(name = "idR",nullable = false)@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})Room room;
…
Spring framework
Spring Data
Les requêtes nomméesVous pouvez aussi utiliser l’annotation @Query
@Query("from Person p where p.nom = ?1 and p.age = ?2")public PersonnemaRequêteAvecQueryDeRechercheParNomEtAge(String nom, int age);
Cela marche aussi avec les requêtes de modification, pour lesquelles il faut
l’annotation @Modifying :
@Query("update Person p set p.nom = :nom where p.id = :id")@Modifyingpublic int metAJourNom(@Param("nom")String nom, @Param("id") Long id);
On peut nommer les paramètres avec @Param
Spring framework
Spring Data
La généricité
Parfois, c’est ennuyeux de répéter la déclaration des méthodes dans le repository de
chaque Bean. C’est pour cela on a besoin d’un repository générique.
@NoRepositoryBeanpublic interface CommonRepository<T,Id extends Serializable> extends JpaRepository<T, Id>{@Query("from #{#entityName} t")List<T> touverTout();}
public interface PersonRepository extends CommonRepository<Person, Long>{}
@GetMapping("/persons")public List<Person> get() {return personrepository.trouverTout();}
Heureusement, cela est déjà fait par
Spring Data, sauf si on a besoin
d’une requête spécifique