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 Web Java Discussion :

Spring Rest API + Docker Compose + Postgres: GET ERROR 500 AFTER POST


Sujet :

Spring Web Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    260
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 260
    Par défaut Spring Rest API + Docker Compose + Postgres: GET ERROR 500 AFTER POST
    Bonjour à tous,

    Tout est résumé dans le titre.
    Je fabrique une API pour un forum de rencontres entre musiciens.

    Mon projet Spring REST est basé sur celui ci:
    https://spring.io/guides/tutorials/rest/

    Au détail près que j'ai une base de données Postgres, et que tout est sur Docker (API + BDD) avec Docker Compose.

    VOICI LA STRUCTURE DU PROJET;

    Nom : Screenshot from 2022-01-17 18-30-14.png
Affichages : 581
Taille : 138,6 Ko



    VOICI LE CODE POUR UNE ENTITE:

    ENTITE:
    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
     
    package com.praline40.MeetZicker.Style;
     
    import com.praline40.MeetZicker.Group.Group;
    import com.praline40.MeetZicker.Musician.Musician;
     
    import javax.persistence.*;
    import java.util.ArrayList;
    import java.util.List;
     
    @Entity
    public class Style {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String name;
     
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
     
        @ManyToMany(mappedBy = "styles")
        private List<Musician> musicians = new ArrayList<>();
     
        @ManyToMany(mappedBy = "styles")
        private List<Group> groups = new ArrayList<>();
     
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
     
        public List<Musician> getMusicians() {
            return musicians;
        }
        public void setMusicians(List<Musician> musicians) {
            this.musicians = musicians;
        }
     
        public List<Group> getGroups() {
            return groups;
        }
        public void setGroups(List<Group> groups) {
            this.groups = groups;
        }
    }
    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
    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
     
    package com.praline40.MeetZicker.Style;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.hateoas.CollectionModel;
    import org.springframework.hateoas.EntityModel;
    import org.springframework.hateoas.IanaLinkRelations;
    import org.springframework.hateoas.MediaTypes;
    import org.springframework.hateoas.mediatype.problem.Problem;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
     
    import java.util.List;
    import java.util.stream.Collectors;
     
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
     
    @RestController //Combination of @Controller and @ResponseBody. Beans returned are converted to/from JSON/XML.
    public class StyleController {
        //@Autowired // Autowire the StyleRepository so that we can retrieve and save data to database.
        private final StyleRepository repository;
        private final StyleModelAssembler assembler; // Injecting StyleModelAssembler into the controller
     
        StyleController(StyleRepository repository, StyleModelAssembler assembler) {
            this.repository = repository;
            this.assembler = assembler;
        }
     
        @GetMapping("/styles/{id}")
        EntityModel<Style> one(@PathVariable Long id) {
     
            Style style = repository.findById(id) //
                    .orElseThrow(() -> new StyleNotFoundException(id));
     
            return assembler.toModel(style);
        }
     
        @GetMapping("/allstyles")
        public String allStyles(){
            return "You wanna know all styles !!";
        }
     
        @GetMapping("/styles")
        CollectionModel<EntityModel<Style>> all() {
     
            List<EntityModel<Style>> styles = repository.findAll().stream()
                    .map(assembler::toModel)
                    .collect(Collectors.toList());
     
            return CollectionModel.of(styles,
                    linkTo(methodOn(StyleController.class).all()).withSelfRel());
        }
     
        @PostMapping("/styles")
        ResponseEntity<?> newStyle(@RequestBody Style newStyle) {
     
            EntityModel<Style> entityModel = assembler.toModel(repository.save(newStyle));
     
            return ResponseEntity //
                    .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()) //
                    .body(entityModel);
        }
     
        @PutMapping("/styles/{id}")
        ResponseEntity<?> replaceStyle(@RequestBody Style newStyle, @PathVariable Long id) {
     
            Style updatedStyle = repository.findById(id) //
                    .map(style -> {
                        style.setName(newStyle.getName());
                        style.setMusicians(newStyle.getMusicians());
                        style.setGroups(newStyle.getGroups());
                        return repository.save(style);
                    }) // s'il n'existe pas déjà on le créé
                    .orElseGet(() -> {
                        newStyle.setId(id);
                        return repository.save(newStyle);
                    });
     
            EntityModel<Style> entityModel = assembler.toModel(updatedStyle);
     
            return ResponseEntity //
                    .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()) //
                    .body(entityModel);
        }
     
        @DeleteMapping("/styles/{id}")
        ResponseEntity<?> deleteStyle(@PathVariable Long id) {
     
            repository.deleteById(id);
     
            return ResponseEntity.noContent().build();
        }
    }

    ASSEMBLER:
    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
     
    package com.praline40.MeetZicker.Style;
     
    import org.springframework.hateoas.EntityModel;
    import org.springframework.hateoas.server.RepresentationModelAssembler;
    import org.springframework.stereotype.Component;
     
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
     
    @Component
    public class StyleModelAssembler implements RepresentationModelAssembler<Style, EntityModel<Style>> {
     
        @Override
        public EntityModel<Style> toModel(Style style) {
     
            return EntityModel.of(style, //
                    linkTo(methodOn(StyleController.class).one(style.getId())).withSelfRel(),
                    linkTo(methodOn(StyleController.class).all()).withRel("styles"));
        }
    }
    NOT FOUND EXCEPTIONS:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    package com.praline40.MeetZicker.Style;
     
    class StyleNotFoundException extends RuntimeException {
     
        StyleNotFoundException(Long id) {
            super("Could not find style " + id);
        }
    }
    REPOSTITORY:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    package com.praline40.MeetZicker.Style;
     
    import org.springframework.data.jpa.repository.JpaRepository;
     
    interface StyleRepository extends JpaRepository<Style, Long> {
    }
    DOCKERFILE:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    FROM openjdk:11
    ADD target/meetzicker.jar meetzicker.jar
    ENTRYPOINT ["java", "-jar","meetzicker.jar"]
    EXPOSE 8080
    DOCKER-COMPOSE:
    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
     
    version: '2.1'
    services:
      API:
        image: 'meetzicker.jar:latest'
        ports:
          - "8080:8080"
        depends_on:
          db:
            condition: service_healthy
        environment:
          - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/${POSTGRES_DB}
          - SPRING_DATASOURCE_USERNAME=${POSTGRES_USER}
          - SPRING_DATASOURCE_PASSWORD=${POSTGRES_PASSWORD}
          - SPRING_JPA_HIBERNATE_DDL_AUTO=update
     
      db:
        image: postgres:${POSTGRES_VERSION}
        ports:
          - "5432:5432"
        environment:
          - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
          - POSTGRES_USER=${POSTGRES_USER}
          - POSTGRES_DB=${POSTGRES_DB}
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U postgres"]
          interval: 10s
          timeout: 5s
          retries: 5



    DANS POSTMAN:

    D'abord un post qui fonctionne:
    Nom : Screenshot from 2022-01-17 18-12-13.png
Affichages : 569
Taille : 46,2 Ko

    Ensuite un get qui crashe:
    GET http://localhost:8080/styles

    Nom : Screenshot from 2022-01-17 18-13-49.png
Affichages : 557
Taille : 34,8 Ko


    NB: tant que je ne fais pas de POST, le GET fonctionne (du moins pour les entités indépendantes)!

    Nom : Screenshot from 2022-01-17 18-14-53.png
Affichages : 565
Taille : 31,3 Ko


    Un post pour un nouvel instrument:

    Nom : Screenshot from 2022-01-17 18-28-08.png
Affichages : 558
Taille : 54,7 Ko


    Ensuite un get, pareil ça plante:
    Nom : Screenshot from 2022-01-17 18-29-18.png
Affichages : 553
Taille : 39,4 Ko


    POUR CE CONTROLLER SIMPLIFIE PAS DE SOUCIS:
    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
     
    package com.praline40.MeetZicker;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.hateoas.CollectionModel;
    import org.springframework.hateoas.EntityModel;
    import org.springframework.hateoas.IanaLinkRelations;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
     
    import java.util.List;
    import java.util.stream.Collectors;
     
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
    import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
     
    @RestController //Combination of @Controller and @ResponseBody. Beans returned are converted to/from JSON/XML.
    public class HomeController {
     
        @GetMapping("/")
        public String home(){
            return "Welcome to Meetzicker !!";
        }
    }
    Nom : Screenshot from 2022-01-17 18-33-32.png
Affichages : 551
Taille : 27,2 Ko


    J'y connais pas grand chose, mais comme ça je dirais que cela vient d'un soucis entre mes relations entre entitées (relations base de données). Car pourquoi cela marcherait-il tant que la base de données est vide (avant POST) ?
    J'avoue j'y suis allé de façon un peu bourrin j'ai fait directement une architecture relationnelle poussée.



  2. #2
    Membre chevronné
    Avatar de Jacques Beauregard
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mai 2015
    Messages
    231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2015
    Messages : 231
    Par défaut
    Bonjour,

    Car pourquoi cela marcherait-il tant que la base de données est vide (avant POST) ?
    On peut l'expliquer par le fait qu'un GET qui retourne aucun résultat va passer, mais dès qu'un élément est présent en bdd (après l'exécution de ton post) le GET échoue et erreur 500 (une erreur 500 est côté serveur justement) car exception lors de la lecture de ta donnée. tu as une stacktrace d'ailleurs ?

    Si j'étais toi donc :

    • Je rajouterais une couche Service qui va appeler ton repository. Ce n'est pas le rôle du Controller. Chaque couche sa responsabilité aidera au passage au debug
    • Dans ta nouvelle couche service je rajouterais un système d'exception lors de l'appelle au repository (qui se charge de faire un SELECT...)
    • As-tu essayé (après ton POST) d'exécuter ton SELECT indépendemment pour voir si la requête passait ?


    Cdlt.
    Il ne faut jamais prendre les gens pour des cons, mais il ne faut pas oublier qu'ils le sont...

    Le guide du débutant pour apprendre à programmer en Java - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre très actif
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    260
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 260
    Par défaut
    Merci pour ta réponse. Je viens de me rendre compte que je n'ai pas été capable de recopier le projet d'exemple correctement, il manque cette classe:

    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
     
     
    package payroll;
     
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.ResponseStatus;
     
     
    /*
    When an EmployeeNotFoundException is thrown, this extra tidbit of Spring MVC configuration is used to render an HTTP 404:
     
    - @ResponseBody signals that this advice is rendered straight into the response body.
    - @ExceptionHandler configures the advice to only respond if an EmployeeNotFoundException is thrown.
    - @ResponseStatus says to issue an HttpStatus.NOT_FOUND, i.e. an HTTP 404.
    - The body of the advice generates the content. In this case, it gives the message of the exception.
     */
     
    @ControllerAdvice
    class EmployeeNotFoundAdvice {
        @ResponseBody
        @ExceptionHandler(EmployeeNotFoundException.class)
        @ResponseStatus(HttpStatus.NOT_FOUND)
        String employeeNotFoundHandler(EmployeeNotFoundException ex) {
            return ex.getMessage();
        }
    }
    C'est sûrement cela le soucis... j'ai pas encore testé je dois bouger, je te tiens au ju !!

  4. #4
    Membre très actif
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    260
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 260
    Par défaut
    J'ai donc toujours le meme soucis;
    J'ai un projet exemple avec Service-repo-controller je vais m'en inspirer.
    Si tu as des liens de tutoriels avec des services je veux bien m'en inspirer aussi.

  5. #5
    Membre chevronné
    Avatar de Jacques Beauregard
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mai 2015
    Messages
    231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2015
    Messages : 231
    Par défaut
    Re,

    As-tu un log d'erreur plus détaillé que "internal servor error" ?
    Il ne faut jamais prendre les gens pour des cons, mais il ne faut pas oublier qu'ils le sont...

    Le guide du débutant pour apprendre à programmer en Java - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre très actif
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juin 2011
    Messages
    260
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2011
    Messages : 260
    Par défaut
    A quel endroit je peut débugguer ça pour avoir plus d'infos ?

    J'avais un service pour les Concerts mais j'ai le même soucis: le post fonctionne mais pas le get.

    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
     
     
    package com.praline40.MeetZicker.Concert;
    import java.time.LocalDate;
    import java.util.List;
     
    import javax.annotation.PostConstruct;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
     
    @Service
    public class ConcertService {
     
        @Autowired
        private ConcertRepository concertRepository;
     
        @Transactional
        @PostConstruct
        public void init() {
            concertRepository.save(new Concert(1L, "JerryTom", null, null, null, "La Roche sur Yon place du marché"));
        }
     
        public List<Concert> findAll() {
            return concertRepository.findAll();
        }
    }

    Apparemment ce service fonctionne puisque lorsque je post un nouveau concert, son ID est "2", ce qui laisse présupposer que le concert de JerryTom créé automatiquement par le service est bien existant.
    Nom : Screenshot from 2022-01-25 11-17-52.png
Affichages : 535
Taille : 55,2 Ko



    Comment dois-je modifier les classes services pour que ça fonctionne ?

    Le problème c'est que dans ces nouvelles technologies web y a tellement de tutoriels différents avec des méthodes sensiblement différentes que l'on ne sait plus à quoi se fier... J'ai suivi ce tutoriel :

    https://spring.io/guides/tutorials/rest/

    Apparemment il s'agit d'une vraie application RestFul 100%.

    Mais il n y a pas de service dans le projet...

Discussions similaires

  1. Réponses: 0
    Dernier message: 16/07/2021, 01h50
  2. Réponses: 1
    Dernier message: 21/10/2020, 17h40
  3. Réponses: 0
    Dernier message: 13/06/2014, 10h18

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