IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Boot Java Discussion :

Apprendre à développer les services REST avec Spring Boot et Spring RestTemplate


Sujet :

Spring Boot Java

  1. #21
    Membre éclairé

    Homme Profil pro
    Ouvrier de l'informatique [ et quelquefois ingénieur logiciel ]
    Inscrit en
    Mars 2013
    Messages
    180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Ouvrier de l'informatique [ et quelquefois ingénieur logiciel ]
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2013
    Messages : 180
    Points : 755
    Points
    755
    Par défaut
    Citation Envoyé par parchemal Voir le message

    Non, c'est valide, à moins que ça soit une différence liée à la version de Spring Boot que tu as choisi. Veille bien à ajouter absolument sa dépendance dans le pom.xml comme ci-dessous:
    bonjour et merci bcp pour cet échange;

    même si c'est secondaire, je reviens sur le fait que ce tuto est réalisé en springboot 1.5; pour ma part j'ai choisi de partir d'un workspace vide pour mieux profiter du tutoriel et le comprendre dans les détails;
    donc pour confirmer ce que j'ai écrit le 14/06, j'ai utilisé la version courante de spring boot (2.0.2) et j'ai constaté les erreurs de build, càd la disparition des éléments que j'ai cités ( findOne(Long) et la clé "security.basic.enabled" ), d'où les adaptations suggérées;
    de plus les annotations JAXB sont inactivées au profit de celles de Jackson. J'ai lu qu'on pourrait activer la prise en charge des annotations JAXB par Jackson, si je le fais je posterai un message avec ma solution du moment;

    pour te répondre j'arrive au stade des tests, et ce sera ma priorité; merci de les avoir fait figurer dans ce tuto

    bon weekend

  2. #22
    Membre chevronné Avatar de jeffray03
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2008
    Messages
    1 501
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 501
    Points : 2 120
    Points
    2 120
    Par défaut Probleme avec Tomcat Serveur embarqué
    Salut
    afin de permettre a Spring Boot de configurer le chargement des pages JSP,
    il faudra mettre dans le fichier pom.xml
    cette dependence :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-jasper</artifactId>
    </dependency>
    Sinon tu auras des pages comme celle-ci :
    Nom : capture_1.png
Affichages : 736
Taille : 45,7 Ko

    et si lorsque du cote client vous essayez de vous connecter avec votre login et mot de passe et que vous recevez ceci comme erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Could not extract response: no suitable HttpMessageConverter found for response type [class User] and content type [application/octet-stream]
    alors vous devez effectuer cette modification dans la classe
    LoginController:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
      @PostMapping(value = "/login")
        public ModelAndView login(@Valid @ModelAttribute("userForm") UserDto userForm,
                BindingResult bindingResult, ModelAndView modelAndView) {
            System.out.println("login .....................");
            modelAndView.setViewName("loginForm");
            if (bindingResult.hasErrors()) {
                return modelAndView;
            } 
            Map<String, String> variables = new HashMap<String, String>(1);
            variables.put("loginName", userForm.getLogin());
            
            MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
            mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM));
            restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);
            
            ResponseEntity<User> userExists =  restTemplate.getForEntity(configurationService.getUrl() +"user/users/{loginName}", User.class, variables);
            System.out.println("URL2 :" + configurationService.getUrl() +"user/users/{loginName}");
            User user = userExists.getBody();
            if (user == null) {//ceci nous évite d'écrire une page de gestion des erreurs
                modelAndView.addObject("saveError", "Aucun utilisateur trouvé avec ce compte");
                return modelAndView;
            }
            modelAndView.setViewName("loginSuccess");
           return modelAndView; 
        }
    le code ajouté est en rouge.

    Eric

  3. #23
    Membre éclairé

    Homme Profil pro
    Ouvrier de l'informatique [ et quelquefois ingénieur logiciel ]
    Inscrit en
    Mars 2013
    Messages
    180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Ouvrier de l'informatique [ et quelquefois ingénieur logiciel ]
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2013
    Messages : 180
    Points : 755
    Points
    755
    Par défaut simplification test Junit du service ?
    bonjour,
    petit a petit je continue avec ce tuto qui est vraiment riche. j'attaque les tests.

    je vous fait part de la légère modification que j'ai effectuée dans les déclarations en haut de la classe de test UserServiceImplTest .

    j'ai remplacé le pavé de code suivant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
       @TestConfiguration //création des Beans nécessaires pour les tests
        static class UserServiceImplTestContextConfiguration {
     
            @Bean//bean de service
            public UserService userService () {
                return new UserServiceImpl();
            }
     
        	@Bean//nécessaire pour encrypter le mot de passe sinon échec des tests
        	public BCryptPasswordEncoder passwordEncoder() {
        		BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        		return bCryptPasswordEncoder;
        	}
        }
    par l'annotation @SpringBootTest

    Voici ce que ça donne :
    (NB : version dans pom.xml : springboot 2.0.2)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class UserServiceImplTest {
     
    	private static Logger LOGGER = LoggerFactory.getLogger(UserServiceImplTest.class);
     
    	@Autowired
    	private UserService userService;
     
    	@MockBean // création d'un mockBean pour UserRepository
    	private UserRepository userRepository;
     
    	@Test
    	public void testGetAllUsers() {
     
    		User user = new User("Dupont", "password", 1);
    		Role role = new Role("USER_ROLE");// initialisation du role utilisateur
    		Set<Role> roles = new HashSet<>();
    		roles.add(role);
    		user.setRoles(roles);
    		List<User> allUsers = Arrays.asList(user);
    		Mockito.when(userRepository.findAll()).thenReturn(allUsers);
     
    		Collection<User> users = userService.getAllUsers();
    		assertNotNull(users);
    		assertEquals(users, allUsers);
    		assertEquals(users.size(), allUsers.size());
     
    		Mockito.verify(userRepository).findAll();
    	}
    ...
    }
    pas de contrepartie au niveau configuration; ça fonctionne très bien d'emblée; y'a t il un inconvénient quelque part ? je n'en ai pas remarqué mais si quelqu'un a des commentaires je suis preneur evidemment.
    merci
    bonne journée

  4. #24
    Membre averti
    Avatar de parchemal
    Homme Profil pro
    Ingénieur Développeur Java
    Inscrit en
    Août 2009
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 144
    Points : 320
    Points
    320
    Par défaut
    Bonjour,

    Je ne vois pas d'inconvénients à ce que vous avez fait. Je trouve ça d'ailleurs plus propre. Dans mon cas, j'ai déclaré moi-même une classe statique interne juste pour initialiser les beans (ce qui permet certains cas, d'ajouter d'autres informations nécessaires aux tests lors de cette initialisation).

    N'hésitez pas à me faire d'autres remarques pour optimiser le tutoriel.

    Courage.

    Bertrand Nguimgo
    Nguimgo Bertrand
    Ingénieur Etudes et Développement JAVA/JEE

    - Guide d'implémentation des services REST avec Spring Boot et Spring RestTemplate
    - Je vous propose de lire le guide d'implémentation du design pattern MVP-GWT
    - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #25
    Membre actif
    Inscrit en
    Juin 2005
    Messages
    578
    Détails du profil
    Informations forums :
    Inscription : Juin 2005
    Messages : 578
    Points : 240
    Points
    240
    Par défaut Comment les infos sur le serveur sont récupérées
    Bonjour

    J'ai commencé à suivre votre excellent tuto et j'ai quelques questions.

    Concernant l'envoi d'une requête "ping" au serveur à l'adresse app.serveur.url = http://localhost:8080/springboot-restserver/, vous dites que l'adresse du serveur est configurée dans le fichier application.properties et accessible grâce à la classe utilitaire ci-dessous:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
    package com.bnguimgo.springbootrestclient.controller;
     
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
     
    @Service
    public class PropertiesConfigurationService{
     
        @Value("${app.serveur.url}") // injection via application.properties
        private String url="";
     
        @Value("${app.serveur.pingServeur}")
        private String pingServeur;
     
        @Value("${app.serveur.ok}")
        private String pingServeurOk;
     
        @Value("${app.serveur.ko}")
        private String pingServeurKo;
     
        @Value("${nextpage.message}")
        private String message;
     
        @Value("${spring.profiles.active}")
        private String profileActif;
        // getters, setters
     
        public String getUrl() {
            return url;
        }
     
        public String getPingServeur() {
            return pingServeur;
        }
     
        public String getPingServeurOk() {
            return pingServeurOk;
        }
     
        public String getPingServeurKo() {
            return pingServeurKo;
        }
     
        public String getMessage() {
            return message;
        }
     
        public String getProfileActif() {
            return profileActif;
        }
    }
    Cette classe utilitaire PropertiesConfigurationService permet de récupérer l'URL du serveur stockée dans le fichier de configuration application.properties.
    Pourtant dans le fichier application.properties, je ne vois toujours pas où est ce que l'url du serveur est récupérée:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #Au démarrage de l'application, en cas d'erreur
    server.error.whitelabel.enabled = false
    #Chargement du profil par defaut dev
    spring.profiles.active=dev
    Merci

  6. #26
    Membre actif
    Inscrit en
    Juin 2005
    Messages
    578
    Détails du profil
    Informations forums :
    Inscription : Juin 2005
    Messages : 578
    Points : 240
    Points
    240
    Par défaut
    Ok je viens de comprendre, c'est le fichier application-dev-properties qui est chargé en production grâce à cette ligne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    spring.profiles.active=dev
    contenue dans le fichier application.properties, c'est bien ça?

  7. #27
    Membre averti
    Avatar de parchemal
    Homme Profil pro
    Ingénieur Développeur Java
    Inscrit en
    Août 2009
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 144
    Points : 320
    Points
    320
    Par défaut
    Citation Envoyé par momjunior Voir le message
    Ok je viens de comprendre, c'est le fichier application-dev-properties qui est chargé en production grâce à cette ligne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    spring.profiles.active=dev
    contenue dans le fichier application.properties, c'est bien ça?
    Tout à fait, l'adresse du serveur se trouve dans le fichier application-dev-properties, car c'est le profil dev qui est activé.
    Nguimgo Bertrand
    Ingénieur Etudes et Développement JAVA/JEE

    - Guide d'implémentation des services REST avec Spring Boot et Spring RestTemplate
    - Je vous propose de lire le guide d'implémentation du design pattern MVP-GWT
    - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #28
    Membre actif
    Inscrit en
    Décembre 2003
    Messages
    491
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 491
    Points : 245
    Points
    245
    Par défaut les sources du tuto
    Bonjour,



    J'ai un souci et je cherche les sources java pour le tuto.

    Mon problème est le suivant: J'ai pu implémenter en partie le Back-end, mais depuis un moment je ne peux plus l'atteindre avec mon browser pour envoyer les requêtes REST.

    Chaque fois que j'envoie quelque chose je tombe sur l'écran pour login et pas moyen de me faire reconnaître.

    Est-ce qu'il est possible de désactiver cette routine d'identification?

    Je ne trouve pas la class: UserRepositoryImpl, contrairement à ce que dit le tuto la class n'a pas eté générée automatiquement.
    Est-ce que l'on peut forcé SpringData à le faire??

    Je ne trouve pas non plus la class: UserRegistrationForm, est-ce que ce serait possible d'avoir le code, cela m'aiderai à comprendre comment faire???

    Merci de répondre

  9. #29
    Membre averti
    Avatar de parchemal
    Homme Profil pro
    Ingénieur Développeur Java
    Inscrit en
    Août 2009
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 144
    Points : 320
    Points
    320
    Par défaut Où trouver les sources du tuto ?
    Bonjour Marc,
    Le lien pour les sources est disponible au chapitre d'introduction, sinon le voici!

    Il faudra juste te connecter avec ton login/pass de developpez.com

    Bon tuto !!
    Nguimgo Bertrand
    Ingénieur Etudes et Développement JAVA/JEE

    - Guide d'implémentation des services REST avec Spring Boot et Spring RestTemplate
    - Je vous propose de lire le guide d'implémentation du design pattern MVP-GWT
    - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  10. #30
    Membre actif
    Inscrit en
    Juin 2005
    Messages
    578
    Détails du profil
    Informations forums :
    Inscription : Juin 2005
    Messages : 578
    Points : 240
    Points
    240
    Par défaut
    Citation Envoyé par Marc_3 Voir le message
    Bonjour,



    J'ai un souci et je cherche les sources java pour le tuto.

    Mon problème est le suivant: J'ai pu implémenter en partie le Back-end, mais depuis un moment je ne peux plus l'atteindre avec mon browser pour envoyer les requêtes REST.

    Chaque fois que j'envoie quelque chose je tombe sur l'écran pour login et pas moyen de me faire reconnaître.

    Est-ce qu'il est possible de désactiver cette routine d'identification?

    Je ne trouve pas la class: UserRepositoryImpl, contrairement à ce que dit le tuto la class n'a pas eté générée automatiquement.
    Est-ce que l'on peut forcé SpringData à le faire??

    Je ne trouve pas non plus la class: UserRegistrationForm, est-ce que ce serait possible d'avoir le code, cela m'aiderai à comprendre comment faire???

    Merci de répondre
    Bonjour

    Pour les sources, regarde au niveau de:

    I. Première partie : Le serveur
    , ensuite
    I-A. Introduction
    et tu trouveras le lien à la dernière ligne du paragraphe :

    Toutes les sources (client et serveur) sont disponibles en téléchargement

  11. #31
    Futur Membre du Club
    Homme Profil pro
    Lille
    Inscrit en
    Avril 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Lille

    Informations forums :
    Inscription : Avril 2019
    Messages : 4
    Points : 5
    Points
    5
    Par défaut demande d'aide suite à la lecture de votre tuto springboot
    Bonjour à tous, merci à @parchemal pour ce super tuto. Je suis tombé dessus en cherchant à faire un webservice rest et une application web cliente permettant de manipuler cette api.
    Je ne sais pas si c'est le bon lieu pour demander cela sinon je m'en excuse et déplacerais le post.
    N'ayant pas une grande expérience dans le domaine, j'espère trouver avec vous des indications pour arriver à mon but.
    Je dois réaliser un webservice qui permet de gérer des vidéos (ajout, modification, suppression d'une vidéo); une vidéo est caractérisé par un titre, un id qui est dans les faits l'identifiant youtube de cette vidéo et un ensemble de tags associé à cette vidéo. et un tag, c'est un id, et un nom.
    Autre chose: une vidéo peut donc être lié à plusieurs tags et inversement, un tag peut être lié à plusieurs vidéos.
    Voici donc mon approche pour le webservice : j'ai définis trois entité Video, Tag, et VideoTag qui est la table issue de l'association entre les deux entité Video et Tag


    -------------------------------------------------------------------------------package entity -------------------------------------------------------------------------------------
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
     
    @Entity(name = "Video")
    @Table (name = "video")
    @NaturalIdCache
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    public class Video implements Serializable{
    	private static final long serialVersionUID = 1L;
     
    	@Id
    	@GeneratedValue(
    	    strategy= GenerationType.AUTO,
    	    generator="increment"
    	)
    	@GenericGenerator(
    	    name = "increment",
    	    strategy = "increment"
    	)
    	@Column(name = "id", updatable = false, nullable = false)
    	private Long id;
     
    	@NaturalId
    	@NotBlank
    	@Column (name = "yid", unique = true)
    	private String youtubeId;
     
    	@NotBlank
    	private String title;
     
    	private String description;
     
    	private Long duration;
     
    	@OneToMany(
    			fetch = FetchType.EAGER, // LAZY me genere une erreur dans la fabrication du JSON
    			mappedBy = "video",
    			cascade = {
    					CascadeType.PERSIST,
    					CascadeType.MERGE
    			},
    			orphanRemoval = true
    			)
    	@JsonManagedReference
    	private Set<VideoTag> tags = new HashSet<>();
     
    	public Video() {}
     
    	public Video(@NotNull String youtubeId, @NotNull String title, String description, Long duration, Set<VideoTag> tags) {
    		super();
    		this.youtubeId = youtubeId;
    		this.title = title;
    		this.description = description;
    		this.duration = duration;
    		this.tags = tags;
    	}
     
    	public Long getId() {
    		return id;
    	}
     
    	public void setId(Long id) {
    		this.id = id;
    	}
     
    	public String getYoutubeId() {
    		return youtubeId;
    	}
     
    	public void setYoutubeId(String youtubeId) {
    		this.youtubeId = youtubeId;
    	}
     
    	public String getTitle() {
    		return title;
    	}
     
    	public void setTitle(String title) {
    		this.title = title;
    	}
     
    	public String getDescription() {
    		return description;
    	}
     
    	public void setDescription(String description) {
    		this.description = description;
    	}
     
    	public Long getDuration() {
    		return duration;
    	}
     
    	public void setDuration(Long duration) {
    		this.duration = duration;
    	}
     
    	public Set<VideoTag> getTags() {
    		return tags;
    	}
     
    	public void setTags(Set<VideoTag> tags) {
    		this.tags = tags;
    	}
     
    	public void addTag(Tag tag) {
    		VideoTag videoTag = new VideoTag(this, tag);
    		tags.add(videoTag);
    	}
     
    	public void removeTag(Tag tag) {
    		for (Iterator<VideoTag> iterator = tags.iterator();iterator.hasNext(); ) {
    			VideoTag videoTag = iterator.next();
     
    			if (videoTag.getVideo().equals(this) && videoTag.getTag().equals(tag)) {
    				iterator.remove();
    				videoTag.setVideo(null);
    				videoTag.setTag(null);
    			}
    		}
    	}
     
    	@Override
    	public boolean equals(Object o) {
    		if (this == o) return true;
     
    		if (o == null || getClass() != o.getClass())
    			return false;
     
    		Video video = (Video) o;
    		return Objects.equals(youtubeId, video.youtubeId);
    	}
     
    	@Override
    	public int hashCode() {
    		return Objects.hash(youtubeId);
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
     
    @Entity(name = "Tag")
    @Table(name = "tag")
    @NaturalIdCache
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    public class Tag implements Serializable {
    	private static final long serialVersionUID = 1L;
     
    	@Id
    	@GeneratedValue(
    	    strategy= GenerationType.AUTO,
    	    generator="increment"
    	)
    	@GenericGenerator(
    	    name = "increment",
    	    strategy = "increment"
    	)
    	@Column(name = "id", updatable = false, nullable = false)
    	private Long id;
     
    	@NotBlank
    	@NaturalId
    	@Column( name = "name", unique = true, nullable = false)
    	private String name;
     
    	@OneToMany(
    			mappedBy = "tag", 
    			cascade = {
    					CascadeType.PERSIST,
    					CascadeType.MERGE
    			},
    			orphanRemoval = true)
    	@JsonIgnore
    	Set<VideoTag> videos = new HashSet<>();
     
    	public Tag() {}
     
    	public Tag(String name) {
    		this.name = name;
    	}
     
    	public Long getId() {
    		return id;
    	}
     
    	public void setId(Long id) {
    		this.id = id;
    	}
     
    	public String getName() {
    		return name;
    	}
     
    	public void setName(String name) {
    		this.name = name;
    	}
     
    	public Set<VideoTag> getVideos() {
    		return videos;
    	}
     
    	public void setVideos(Set<VideoTag> videos) {
    		this.videos = videos;
    	}
     
    	@Override
    	public boolean equals(Object o) {
    		if (this == o) return true;
    		if (o == null || getClass() != o.getClass()) return false;
    		Tag tag = (Tag) o;
    		return Objects.equals(name, tag.name);
    	}
     
    	@Override
    	public int hashCode() {
    		return Objects.hash(name);
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
     
    @Entity(name = "VideoTag")
    @Table(name = "video_tag")
    public class VideoTag implements Serializable{
    	private static final long serialVersionUID = 1L;
    	private static final Boolean DEFAULT_VALUE_MAIN_TAG = false;
     
    	@EmbeddedId
    	@JsonIgnore
        private VideoTagId id;
     
    	@ManyToOne
    	@MapsId("videoId")
    	@JsonBackReference
        private Video video;
     
        @ManyToOne
        @MapsId("tagId")
        private Tag tag;
     
        @JsonIgnore
        @Column(name = "is_main_tag", nullable = false, columnDefinition = "BOOLEAN")
        private Boolean isMainTag;
     
        protected VideoTag() {}
     
        public VideoTag(Video video, Tag tag) {
        	this(video, tag, DEFAULT_VALUE_MAIN_TAG);
        }
     
        public VideoTag(Video video, Tag tag, Boolean isMainTag) {
            this.video = video;
            this.tag = tag;
            this.isMainTag = isMainTag;
     
            // creation de la clé primaire
            this.id = new VideoTagId(video.getId(), tag.getId());
     
            // mise à jour des relations pour assurer l'intégrité référentielle
            video.getTags().add(this);
    		tag.getVideos().add(this);
     
        }
     
        public VideoTagId getId() {
    		return id;
    	}
     
    	public void setId(VideoTagId id) {
    		this.id = id;
    	}
     
    	public Video getVideo() {
    		return video;
    	}
     
    	public void setVideo(Video video) {
    		this.video = video;
    	}
     
    	public Tag getTag() {
    		return tag;
    	}
     
    	public void setTag(Tag tag) {
    		this.tag = tag;
    	}
     
    	public Boolean getIsMainTag() {
    		return isMainTag;
    	}
     
    	public void setIsMainTag(Boolean isMainTag) {
    		this.isMainTag = isMainTag;
    	}
     
    	@Override
        public boolean equals(Object o) {
            if (this == o) return true;
     
            if (o == null || getClass() != o.getClass())
                return false;
     
            VideoTag that = (VideoTag) o;
            return Objects.equals(video, that.video) &&
                   Objects.equals(tag, that.tag);
        }
     
        @Override
        public int hashCode() {
            return Objects.hash(video, tag);
        }
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
     
    @Embeddable
    public class VideoTagId  implements Serializable {
    	private static final long serialVersionUID = 1L;
     
    	@Column(name = "vid")
    	private Long videoId;
     
    	@Column(name = "tid")
    	private Long tagId;
     
        protected VideoTagId() {}
     
        public VideoTagId(Long videoId, Long tagId) {
            this.videoId = videoId;
            this.tagId = tagId;
        }
     
        public Long getVideoId() {
    		return videoId;
    	}
     
    	public void setVideoId(Long videoId) {
    		this.videoId = videoId;
    	}
     
    	public Long getTagId() {
    		return tagId;
    	}
     
    	public void setTagId(Long tagId) {
    		this.tagId = tagId;
    	}
     
    	@Override
        public boolean equals(Object o) {
            if (this == o) return true;
     
            if (o == null || getClass() != o.getClass())
                return false;
     
            VideoTagId that = (VideoTagId) o;
            return Objects.equals(videoId, that.videoId) &&
                   Objects.equals(tagId, that.tagId);
        }
     
        @Override
        public int hashCode() {
            return Objects.hash(videoId, tagId);
        }
    }

    ------------------------------------------------------------------------package repository -----------------------------------------------------------------------------------------
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    @Repository
    public interface TagRepository extends JpaRepository<Tag, Long> {
    	Optional<Tag> findByName(String name);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    @Repository
    public interface VideoRepository extends JpaRepository<Video, Long>{
            @Query(value="SELECT v.* FROM video_tag vt JOIN tag t ON t.id = vt.tag_id JOIN video v ON v.id = vt.video_id WHERE t.name IN ('') UNION SELECT v.* FROM video_tag vt JOIN tag t ON t.id = vt.tag_id JOIN video v ON v.id = vt.video_id WHERE t.name IN (:mtags) OR t.name IN (:stags);", nativeQuery=true) // pouvoir recuperer les vidéos qui matchent les tags principaux se trouvant mtags et ceux qui matchent les tags sécondaires stags avec en premier, les videos matchant les tags contenus dans mtags
    	List<Video> findAllVideosByTags(@Param("mtags") List<String> mtags,@Param("stags")  List<String> stags);
    }

    -----------------------------------------------------------------------package controller --------------------------------------------------------------------------------
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    @RestController
    @RequestMapping(path = "/tags", produces = MediaType.APPLICATION_JSON_VALUE)
    public class TagController {
    	@Autowired ITagService tagService;
     
     
    	  @GetMapping
    	  ResponseEntity<Collection<Tag>> all() {
    	    return new ResponseEntity<>(tagService.findAll(), HttpStatus.OK);
    	  }
     
    	  @PostMapping
    	  ResponseEntity<Tag> addTag(@RequestBody Tag newTag) {
    	    return new ResponseEntity<>(tagService.save(newTag), HttpStatus.CREATED);
    	  }
     
     
    	  @GetMapping("/{id}")
    	  ResponseEntity<Tag> getOneTag(@PathVariable Long id) {
    	    return tagService.findById(id)
    	    		.map(tag -> {
    	    			return new ResponseEntity<>(tag, HttpStatus.OK);
    	    		})
    	    		.orElseThrow(() -> new ResourceNotFoundException("Tag", id));
    	  }
     
    	  @PutMapping("/{id}")
    	  ResponseEntity<Tag> replaceTag(@RequestBody Tag newTag, @PathVariable Long id) {
    		  return tagService.findById(id)
    				  .map(tag -> {
    					  tag.setName(newTag.getName());
    					  return new ResponseEntity<Tag>(tagService.save(tag), HttpStatus.OK);
    				  })
    				  .orElseGet(() -> {
    					  newTag.setId(id);
    					  return new ResponseEntity<Tag>(tagService.save(newTag), HttpStatus.CREATED);
    				  });
    	  }
     
    	  @DeleteMapping("/{id}")
    	  ResponseEntity<Void> deleteTag(@PathVariable Long id) {
    		  tagService.deleteById(id);
    		  return new ResponseEntity<Void>(HttpStatus.OK);
    	  }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
     
    @RestController
    @RequestMapping(path = "/videos", produces = MediaType.APPLICATION_JSON_VALUE)
    public class VideoController {
    	@Autowired private IVideoService videoService;
     
    	@GetMapping
    	List<Video> all() {
    		return videoService.findAllVideos();
    	}
     
     
    	@GetMapping("/{id}")
    	Video one(@PathVariable Long id) {
    		Video video = videoService.findVideoById(id);
    		return video;
    	}
     
    	@GetMapping("/search")
    	ResponseEntity<Collection<Video>> findVideosByTagNames(@RequestParam("mt") List<String> mtags, @RequestParam("st") List<String> stags) {
    		if(mtags.isEmpty() ) {
    			mtags.add("");
    		}
    		if(stags.isEmpty()) {
    			stags.add("");
    		}
    		return new ResponseEntity<>(
    				videoService.findVideosByTags(mtags, stags).stream()
    				.distinct()
    				.collect(Collectors.toList()), HttpStatus.OK);
    	}
     
    	@GetMapping("{id}/tags")
    	ResponseEntity<Collection<Tag>> getTagsForIdVideo(@PathVariable Long id) {
    		 return new ResponseEntity<>(videoService.findTagsByIdVideo(id), HttpStatus.OK);
    	}
     
    	@PostMapping
    	Video newVideo(@RequestBody Video newVideo) {
    		return videoService.insertVideo(newVideo);
    	}
    //	@PostMapping
    //	ResponseEntity<Object> newVideo(@RequestBody Video newVideo) {
    //		Video savedVideo = videoService.insertVideo(newVideo);
    //		
    //		URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
    //				.buildAndExpand(savedVideo.getId()).toUri();
    //		return ResponseEntity.created(location).build();
    //	}
     
    	@PutMapping("/{id}/tags/aid")
    	Video addTagsByIdsToVideo(@PathVariable(name = "id") Long idVideo, @RequestParam (name = "ids") List<Long> tagIds) {
    		return videoService.addTagsByIdsToVideo(idVideo, tagIds);
    	}
     
    	@PutMapping("/{id}/tags/aname")
    	Video addTagsByNamesToVideo(@PathVariable(name = "id") Long idVideo, @RequestParam (name = "names") List<String> tagNames) {
    		return videoService.addTagsByNamesToVideo(idVideo, tagNames);
    	}
     
     
    	@PutMapping("/{id}/tags/did")
    	Video delTagsByIdsToVideo(@PathVariable(name = "id") Long idVideo, @RequestParam (name = "ids") List<Long> tagIds) {
    		return videoService.delTagsByIdsToVideo(idVideo, tagIds);
    	}
     
    	@PutMapping("/{id}/tags/dname")
    	Video delTagsByNamesToVideo(@PathVariable(name = "id") Long idVideo, @RequestParam (name = "names") List<String> tagNames) {
    		return videoService.delTagsByNamesToVideo(idVideo, tagNames);
    	}
     
    	@PutMapping("/{id}")
    	Video replaceVideo(@RequestBody Video newVideo, @PathVariable Long id) {
    		videoService.findVideoById(id);
    		return videoService.updateVideoById(newVideo, id);
    	}
    //	@PutMapping("/{id}")
    //	ResponseEntity<Object> replaceVideo(@RequestBody Video newVideo, @PathVariable Long id) {
    //		Optional<Video> video = videoService.findById(id);
    //		if(!video.isPresent()) {
    //			return ResponseEntity.notFound().build();
    //		}
    //		newVideo.setId(id);
    //		Video updatedVideo = videoService.save(newVideo);
    //		URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
    //				.buildAndExpand(updatedVideo.getId()).toUri();
    //		return ResponseEntity.created(location).build();
    //	}
     
    	@DeleteMapping("/{id}")
    	ResponseEntity<Object> deleteVideo(@PathVariable Long id) {
    		videoService.deleteVideoById(id);
    		return ResponseEntity.noContent().build();
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    @ControllerAdvice
    public class ErrorAdvice {
    	  @ResponseBody
    	  @ExceptionHandler(ResourceNotFoundException.class)
    	  @ResponseStatus(HttpStatus.NOT_FOUND)
    	  String videoNotFoundHandler(ResourceNotFoundException ex) {
    	    return ex.getMessage();
    	  }
    }


    ------------------------------------------------------------------------------package service-----------------------------------------------------------------------------------------------------
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
     
    @Service
    public class VideoServiceImpl implements IVideoService {
    	@Autowired private VideoRepository videoRepository;
    	@Autowired private ITagService tagService;
     
    	@Override
    	public Video findVideoById(Long id) {
    		return videoRepository.findById(id)
    				.orElseThrow(() -> new ResourceNotFoundException("Video", id));
    	}
     
    	@Override
    	public List<Video> findAllVideos() {
    		return videoRepository.findAll();
    	}
     
    	@Override
    	public List<Video> findVideosByTags(List<String> mtags, List<String> stags) {
    		List<Video> videos = videoRepository.findAllVideosByTags(mtags, stags);
    		return videos;
    	}
     
    	@Override
    	public Video updateVideoById(Video newVideo, Long id) {
    		return videoRepository.findById(id)
    				.map(video -> {
    					video.setYoutubeId(newVideo.getYoutubeId());
    					video.setTitle(newVideo.getTitle());
    					video.setDescription(newVideo.getDescription());
    					video.setDuration(newVideo.getDuration());
    					return videoRepository.save(video);
    				})
    				.orElseGet(() -> {
    					newVideo.setId(id);
    					return videoRepository.save(newVideo);
    				});
    	}
     
    	@Override
    	public Video insertVideo(Video video) {
    		return videoRepository.save(video);
    	}
     
    	@Override
    	public void deleteVideoById(Long id) {
    		Video video = findVideoById(id);
    		videoRepository.delete(video);
    	}
     
    	@Transactional
    	@Override
    	public Video addTagsByIdsToVideo(Long idVideo, List<Long> idsTag) {
    		Video video = findVideoById(idVideo);
    		for(Long tagId : idsTag) {
    			Optional<Tag> tagOptional = tagService.findById(tagId);
    			if(tagOptional.isPresent()) {
    				video.addTag(tagOptional.get());
    			}
    		}
    		return save(video);
    	}
     
    	@Override
    	public Video delTagsByIdsToVideo(Long idVideo, List<Long> idsTag) {
    		Video video = findVideoById(idVideo);
    		for(Long tagId : idsTag) {
    			Optional<Tag> tagOptional = tagService.findById(tagId);
    			// si tag present on l'enleve de la video sinon on fait rien
    			if(tagOptional.isPresent()) {
    				video.removeTag(tagOptional.get());
    			}
    		}
    		return save(video);
    	}
     
    	@Override
    	public Video addTagsByNamesToVideo(Long idVideo, List<String> names) {
    		Video video = findVideoById(idVideo);
    		for(String tagName : names) {
    			Optional<Tag> tagOptional = tagService.findByName(tagName);
    			// si tag present on l'ajoute
    			Tag tag;
    			if(tagOptional.isPresent()) {
    				tag = tagOptional.get();
    			}else { // si non present on le cree et on l'ajoute
    				tag = tagService.save(new Tag(tagName));
    			}
    			video.addTag(tag);
    		}
    		return save(video);
    	}
     
    	@Override
    	public Video delTagsByNamesToVideo(Long idVideo, List<String> names) {
    		Video video = findVideoById(idVideo);
    		for(String tagName : names) {
    			Optional<Tag> tagOptional = tagService.findByName(tagName);
    			// si tag present on l'enleve de la video sinon on fait rien
    			if(tagOptional.isPresent()) {
    				video.removeTag(tagOptional.get());
    			}
    		}
    		return save(video);
    	}
     
    	@Override
    	public Video updateVideo(Video video) {
    		return videoRepository.save(video);
    	}
     
    	@Override
    	public Optional<Video> findById(Long id) {
    		return videoRepository.findById(id);
    	}
     
    	@Override
    	public Video save(Video newVideo) {
    		return videoRepository.save(newVideo);
    	}
     
    	@Override
    	public List<Tag> findTagsByIdVideo(Long idVideo) {
    		return findVideoById(idVideo).getTags().stream()
    				.map(VideoTag::getTag)
    				.collect(Collectors.toList());
    	}
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    public interface IVideoService {
    	Video findVideoById(Long id);
    	List<Video> findAllVideos();
    	List<Video> findVideosByTags(List<String> mtags, List<String> stags);
    	Video updateVideo(Video video);
    	Video insertVideo(Video video);
    	Video updateVideoById(Video newVideo, Long id);
    	void deleteVideoById(Long id);
    	Video addTagsByIdsToVideo(Long idVideo, List<Long> idsTag);
    	Video delTagsByIdsToVideo(Long idVideo, List<Long> idsTag);
    	Video addTagsByNamesToVideo(Long idVideo, List<String> names);
    	Video delTagsByNamesToVideo(Long idVideo, List<String> names);
    	Optional<Video> findById(Long id);
    	Video save(Video newVideo);
    	List<Tag> findTagsByIdVideo(Long idVideo);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    public interface ITagService {
    	public Tag save(Tag tag);
    	public List<Tag> findAll();
    	public Optional<Tag> findById(Long id);
    	public List<Tag> saveAll(Iterable<Tag> tags);
    	public void deleteById(Long id);
    	public Tag getOne(Long id);
    	public void delete(Tag tag);
    	public void deleteAll(Iterable<Tag> tags);
    	public void deleteAll();
    	public boolean existsById(Long id);
    	public Long count();
    	public Optional<Tag> findByName(String name);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
     
    @Service
    public class TagServiceImpl implements ITagService {
    	@Autowired private TagRepository tagRepository;
     
    	public Tag save(Tag tag) {
    		return tagRepository.save(tag);
    	}
     
    	public List<Tag> findAll() {
    		return tagRepository.findAll(Sort.by(Sort.Direction.ASC, "id"));
    	}
     
    	public Optional<Tag> findById(Long id) {
    		return tagRepository.findById(id);
    	}
     
    	public List<Tag> saveAll(Iterable<Tag> tags) {
    		return tagRepository.saveAll(tags);
    	}
     
    	public void deleteById(Long id) {
    		Tag tag = tagRepository.findById(id).get();
    		if(tag != null && !tag.getVideos().isEmpty()) {
    			tag.getVideos().clear();
    		}
    		tagRepository.delete(tag);
    	}
     
    	public Tag getOne(Long id) {
    		return tagRepository.getOne(id);
    	}
     
    	public void delete(Tag tag) {
    		tagRepository.delete(tag);
    	}
     
    	public void deleteAll(Iterable<Tag> tags) {
    		tagRepository.deleteAll(tags);
    	}
     
    	public void deleteAll() {
    		tagRepository.deleteAll();
    	}
     
    	public boolean existsById(Long id) {
    		return tagRepository.existsById(id);
    	}
     
    	public Long count() {
    		return tagRepository.count();
    	}
     
    	@Override
    	public Optional<Tag> findByName(String name) {
    		return tagRepository.findByName(name);
    	}
    }
    __________________________________________APP principal__________________________________________________________
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    @SpringBootApplication
    public class ProjetVideoApplication {
    	public static void main(String[] args) {
    		SpringApplication.run(ProjetVideoApplication.class, args);
    	}
    }
    Je souhaite obtenir une présentation comme celle-ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    [
    	{
    		"id" : 1,
    		"youtubeId": "hgfdgdU_riE",
    		"title": "Video de test d'ajout",
    		"description": "Une video pour tester l'ajout avec POST",
    		"duration": 300,
    		"tags" : [
    			{
    				"id" : 1,
    				"name" : "tuto"
    			},
    			{
    				"id" : 2,
    				"name" : "rest"
    			}
    		]
    	},
    	{
    		"id" : 2,
    		"youtubeId": "hgfdgdU_riE",
    		"title": "Autre Video",
    		"description": "autre description",
    		"duration": 300,
    		"tags" : [
    			{
    				"id" : 1,
    				"name" : "tuto"
    			}
    		]
    	},
    	{
    		"id" : 3,
    		"youtubeId": "hgfdgdU_riE",
    		"title": "Autre Video",
    		"description": "autre description",
    		"duration": 300,
    		"tags" : []
    	}
    ]
    Ceci est la partie webservice
    j'ai pas encore commencé le client.
    Mais déjà j'aimerais pouvoir être sûr que le webservice fonctionne avec tous les besoins c'est-à-dire la recherche des vidéos par liste de tags principaux et secondaires.
    j'aimerais avoir votre avis et suggestions sachant que pour l'instant la suppression d'un tag en passant par le service tagservice entraine la suppression du lien dans VideoTag (jusque là ça va), mais aussi la vidéo correspondante. Pareil quand j'enleve un tag d'une vidéo je veux juste enlever le lien entre le tag et la vidéo mais ça ne fonctionne pas, le lien n'est pas supprimé dans videoTag.
    Merci pour vos retour.

  12. #32
    Membre averti
    Avatar de parchemal
    Homme Profil pro
    Ingénieur Développeur Java
    Inscrit en
    Août 2009
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 144
    Points : 320
    Points
    320
    Par défaut
    Citation Envoyé par uNouss Voir le message
    Pareil quand j'enleve un tag d'une vidéo je veux juste enlever le lien entre le tag et la vidéo mais ça ne fonctionne pas, le lien n'est pas supprimé dans videoTag
    Bonjour,
    Votre approche est bonne. Concernant votre question sur la suppression ou non des dépendances, il faut voir du côté de l'utilisation JPA Cascade Types (une petite recherche sur le web vous donne le résultat ci-dessous)

    The cascade types supported by the Java Persistence Architecture are as below:

    CascadeType.PERSIST : cascade type presist means that save() or persist() operations cascade to related entities.
    CascadeType.MERGE : cascade type merge means that related entities are merged when the owning entity is merged.
    CascadeType.REFRESH : cascade type refresh does the same thing for the refresh() operation.
    CascadeType.REMOVE : cascade type remove removes all related entities association with this setting when the owning entity is deleted.
    CascadeType.DETACH : cascade type detach detaches all related entities if a “manual detach” occurs.
    CascadeType.ALL : cascade type all is shorthand for all of the above cascade operations.

    Espérant que ça vous aide à avancer.
    Nguimgo Bertrand
    Ingénieur Etudes et Développement JAVA/JEE

    - Guide d'implémentation des services REST avec Spring Boot et Spring RestTemplate
    - Je vous propose de lire le guide d'implémentation du design pattern MVP-GWT
    - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  13. #33
    Futur Membre du Club
    Homme Profil pro
    Lille
    Inscrit en
    Avril 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Lille

    Informations forums :
    Inscription : Avril 2019
    Messages : 4
    Points : 5
    Points
    5
    Par défaut
    Bonjour,
    Merci pour votre retour et je suis content de savoir que l'approche que j'ai eu est dans le bon sens.
    Citation Envoyé par parchemal Voir le message
    Concernant votre question sur la suppression ou non des dépendances, il faut voir du côté de l'utilisation JPA Cascade Types (une petite recherche sur le web vous donne le résultat ci-dessous)
    Je vais explorer cette piste et voir ce qu'il en revient mais j'ai aussi une erreur que j'avais pas remarqué. en faite il y a un retour dans Eclipse
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/api/v1].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/api/v1] threw exception [Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.leaderinfo.youtube.entity.Tag.videos, could not initialize proxy - no Session] with root cause
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.leaderinfo.youtube.entity.Tag.videos, could not initialize proxy - no Session
    quand j'essaie de faire un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DELETE http://localhost:8080/api/v1/videos/{id}
    malgré le fait que le tag soit supprimé dans la base de donnée.

    Autre point j'aimerais à présent commencé la deuxième phase qui est de faire l'application web cliente qui via des formulaires et l'exploitation de l'api permettra de manipuler les vidéos.
    J'ai suivi votre tuto et j'ai un certain nombre de classe qui sont déprécié avec la version de spring que j'utilise et pareil je n'arrive pas à lancer en même temps le client et le serveur. J'imagine que pour ce dernier point je dois juste changer le port de tomcat pour avoir les deux lancé pour tester votre code par exemple.

  14. #34
    Membre averti
    Avatar de parchemal
    Homme Profil pro
    Ingénieur Développeur Java
    Inscrit en
    Août 2009
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 144
    Points : 320
    Points
    320
    Par défaut
    Citation Envoyé par uNouss Voir le message
    J'imagine que pour ce dernier point je dois juste changer le port de tomcat pour avoir les deux lancé pour tester votre code par exemple.
    Bonjour,

    Il faut démarrer le serveur à part, et ensuite le client, car l'application est développée dans l'esprit de séparer complètement le back-end du front-end

    Courage
    Nguimgo Bertrand
    Ingénieur Etudes et Développement JAVA/JEE

    - Guide d'implémentation des services REST avec Spring Boot et Spring RestTemplate
    - Je vous propose de lire le guide d'implémentation du design pattern MVP-GWT
    - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  15. #35
    Futur Membre du Club
    Homme Profil pro
    Lille
    Inscrit en
    Avril 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Lille

    Informations forums :
    Inscription : Avril 2019
    Messages : 4
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par parchemal Voir le message
    Il faut démarrer le serveur à part, et ensuite le client, car l'application est développée dans l'esprit de séparer complètement le back-end du front-end
    Y a t'il un moyen de lancer les deux sur le même post ?

    En changeant le port j'arrive à lancer les deux mais j'obtiens cette erreur depuis le client.
    Nom : errorClient.png
Affichages : 592
Taille : 21,7 Ko

  16. #36
    Membre averti
    Avatar de parchemal
    Homme Profil pro
    Ingénieur Développeur Java
    Inscrit en
    Août 2009
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 144
    Points : 320
    Points
    320
    Par défaut
    Citation Envoyé par uNouss Voir le message
    Y a t'il un moyen de lancer les deux sur le même post ?
    Oui, tu peux lancer les deux sur le même poste, j'ai d'ailleurs tout fait sur le même poste. L'erreur que tu obtiens (Une erreur est survenue !!!.) est bien logique, car c'est l'erreur par défaut que j'ai configurée dans le fichier error.jsp, essaie de te mettre en mode debug, en configurant ton débogueur sur le même port que celui du serveur, tu n'es pas loin du but.

    Tu peux aussi lire la contribution de jeffray03 ci-dessous dans ce forum pour ajouter si possible la dépendance Tomcat, selon ta version de Spring Boot. Je pense que c'est ça qui explique ton erreur, donc je te conseille fortement d'ajouter cette dépendance.

    Je te mets cette dépendance ici:

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-jasper</artifactId>
    </dependency>

    Courage
    Nguimgo Bertrand
    Ingénieur Etudes et Développement JAVA/JEE

    - Guide d'implémentation des services REST avec Spring Boot et Spring RestTemplate
    - Je vous propose de lire le guide d'implémentation du design pattern MVP-GWT
    - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  17. #37
    Futur Membre du Club
    Homme Profil pro
    Lille
    Inscrit en
    Avril 2019
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Lille

    Informations forums :
    Inscription : Avril 2019
    Messages : 4
    Points : 5
    Points
    5
    Par défaut
    Merci pour votre retour, en effet en ajoutant la dépendance, l'erreur d'interprétation des tag jstl a bien disparu. J'avais cette dépendance dans mon pom.xml mais pas la bonne version. mais là ça fonctionne et je vais pouvoir m'inspirer de votre client pour faire le mien.

  18. #38
    Membre éprouvé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2007
    Messages
    697
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2007
    Messages : 697
    Points : 1 241
    Points
    1 241
    Par défaut
    Bonjour et merci pour ce tutoriel très complet.

    Une question, dans la partie I-B-1-b. Structure de l'application, on est d'accord qu'on présente d'abord le setup d'un application jar et ensuite le setup d'une application war ?

  19. #39
    Membre actif
    Inscrit en
    Juin 2005
    Messages
    578
    Détails du profil
    Informations forums :
    Inscription : Juin 2005
    Messages : 578
    Points : 240
    Points
    240
    Par défaut Méthodes findOne et delete non reconnues
    Bonjour

    Il me semble qu'il y ait des problèmes de compatibilité concernant la méthode findOne et delete qui se trouvent dans UserController.java.

    Dans le service User, la méthode findOne(Long) n'est plus disponible et j'ai lu dans les commentaires du tuto qu'il fallait la remplacer par findById et la signature devient "Optional<User> getUserById(Long id) throws BusinessResourceException;". Et ça marche.

    Maintenant dans la Class UserController.java , je suis obligé de changer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    User userToUpdate = userService.getUserById(id);
    par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Optional<User> userToUpdate = userService.getUserById(id);
    Sauf que les méthodes getRoles, setLogin, setPassword, setActive, saveOrUpdateUser me génèrent des erreurs du genre:

    The method getRoles() is undefined for the type Optional<User>
    Nom : spring.PNG
Affichages : 2199
Taille : 54,3 Ko

    Ensuite concernant la méthode delete:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	@Override
    	@Transactional(readOnly=false)
    	public void deleteUser(Long id) throws BusinessResourceException {
    		try{
    			userRepository.delete(id);
    		}catch(Exception ex){
    			throw new BusinessResourceException("Delete User Error", "Erreur de suppression de l'utilisateur avec l'identifiant: "+id, HttpStatus.INTERNAL_SERVER_ERROR);
    		}		
    	}
    j'ai ce message d'erreur:

    The method delete(User) in the type CrudRepository<User,Long> is not applicable for the arguments (Long)
    Par quelle méthode dois-je la remplacer pour régler ce problème?

    Merci

  20. #40
    Membre averti
    Avatar de parchemal
    Homme Profil pro
    Ingénieur Développeur Java
    Inscrit en
    Août 2009
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 144
    Points : 320
    Points
    320
    Par défaut
    Bonjour,

    Désolé pour ma réponse tardive. Toutes les erreurs que tu rencontres sont liées à l'utilisation de la nouvelle version de Spring Boot qui a déplacé certaines librairies vers d'autres packages. Pour ce qui est de findOne(Long), oui il faut remplacer par findById(Long), ce qui induit également les changements dans les autres packages.

    Je suis entrain d'écrire une nouvelle version du tuto.

    Cordialement
    Bertrand Nguimgo
    Nguimgo Bertrand
    Ingénieur Etudes et Développement JAVA/JEE

    - Guide d'implémentation des services REST avec Spring Boot et Spring RestTemplate
    - Je vous propose de lire le guide d'implémentation du design pattern MVP-GWT
    - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

Discussions similaires

  1. [Web Services] Tutoriel sur le développement des services REST avec Spring 3
    Par regis1512 dans le forum Spring
    Réponses: 0
    Dernier message: 11/02/2015, 12h34
  2. Premier développement de services web avec Spring-WS
    Par Arnaud_03 dans le forum Services Web
    Réponses: 5
    Dernier message: 02/12/2008, 16h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo