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

Consommer du JSON avec un @RestController


Sujet :

Spring Java

  1. #1
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    octobre 2013
    Messages
    993
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : octobre 2013
    Messages : 993
    Points : 2 443
    Points
    2 443
    Par défaut Consommer du JSON avec un @RestController
    Bonjour,

    Je poste ici car ma question porte sur plusieurs briques, de Spring mais surtout sur Spring MVC.

    Je voudrais créer des services web pour ajouter des entity depuis du JSON, le service avec des paramètres standards fonctionne.

    J'ai fait un code teste.

    J'ai une entité Personne que je souhaite créer depuis un service.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    @Entity
    @JsonRootName("personne	")
    public class Personne {
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	@JsonIgnore
    	private int id;
        @JsonProperty("nom")
    	private String nom;
        @JsonProperty("prenom")
    	private String prenom;
    Comme l'id est généré, je ne souhaite pas l'récupérer dans les arguments, c'est pourquoi j'ai mis l'annotation "ignore".

    J'ai ajouté deux services un pour récupérer un nouvel item et un autre pour en récupérer plusieurs à la fois les deux depuis du JSON.
    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
     
    	@PostMapping(path = "consume", consumes="application/json")
    	@ResponseStatus(code = HttpStatus.CREATED)
    	public void saveJSON(@RequestBody Personne personne) {
    LOGGER.debug("Personne founf : " + personne, null, personne, personne, personne, personne, personne, personne, personne, personne);
     
    		personneService.save(personne);
    	}
     
    	@PostMapping(path = "/consumeAll", consumes = "application/json")
    	public HttpStatus saveAllJSON(@RequestBody List<Personne> personnes) {
    LOGGER.debug("Personne founf : " + personnes.size());
     
    		personneService.saveAll(personnes);
     
    		return HttpStatus.CREATED;
    	}
    Je tente de contacter mon service avec curl car postman n'est pas très accessible pour moi.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    curl -H "Content-type: application/json" -d '{"id":"1","nom":"smith","prenom":"john"}' http://localhost:8080/personne/consume
    Mais j'obtiens toujours une erreur 400.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    {"timestamp":"2022-11-18T10:13:22.547+00:00","status":400,"error":"Bad Request","trace":"org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character (''' (code 39)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character (''' (code 39)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 2]\r\n\tat org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:391)\r\n\tat org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:343)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:185)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:160)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:133)\r\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:696)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:779)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:834)\r\nCaused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character (''' (code 39)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 2]\r\n\tat com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2391)\r\n\tat com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:735)\r\n\tat com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:659)\r\n\tat com.fasterxml.jackson.core.json.UTF8StreamJsonParser._handleUnexpectedValue(UTF8StreamJsonParser.java:2737)\r\n\tat com.fasterxml.jackson.core.json.UTF8StreamJsonParser._nextTokenNotInObject(UTF8StreamJsonParser.java:902)\r\n\tat com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:794)\r\n\tat com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4761)\r\n\tat com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4667)\r\n\tat com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3682)\r\n\tat org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:380)\r\n\t... 51 more\r\n","message":"JSON parse error: Unexpected character (''' (code 39)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character (''' (code 39)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 2]","path":"/personne/consume"}
    Est-ce que j'ai mal mappé l'uurl ?
    Est-ce que je peux ignorer l'id dans les paramètres ? Car JPA qui va le définir pour moi.

    Cordialement
    Consultez mes articles sur l'accessibilité numérique :

    Comment rendre son application SWING accessible aux non voyants
    Créer des applications web accessibles à tous

    YES WE CAN BLANCHE !!!

    Rappelez-vous que Google est le plus grand aveugle d'Internet...
    Plus c'est accessible pour nous, plus c'est accessible pour lui,
    et meilleur sera votre score de référencement !

  2. #2
    Membre averti

    Profil pro
    Inscrit en
    janvier 2009
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : janvier 2009
    Messages : 230
    Points : 443
    Points
    443
    Billets dans le blog
    5
    Par défaut
    Il faut différentier les couche (à minima), et surtout les responsabilités de chaque classes.

    Le REST n'a rien à voir avec le service et la DAO.

    Je pense même qu'il faut différentier la DTO (à transfèrer) et l'entité (qui mappe la BDD, en résumé Hibernate).

    Si tu passe un simple POJO à la con (qui du coup est une DTO), et sans annotation, ça marchera.

    A toi d'appeler le service dans le controller, et dans le service, dans lequel tu injectes la DAO, faire le mapping et sauver.

  3. #3
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    octobre 2013
    Messages
    993
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : octobre 2013
    Messages : 993
    Points : 2 443
    Points
    2 443
    Par défaut
    Merci pour ta réponse.

    Là je ne comprends pas j'pensais avoir séparé les couches.

    J'ai une classe par annotation Spring
    - @Entity pour mon modèle , qui ne connais pas les autres.
    - @Repository, qui dérive de CrudRepository, qui se base sur le modèle
    - @Service qui appelle le repository
    - Le @RestController, qui fait appelle au service

    Il n'y a pas de méllange.

    Je pensais qu'Spring pouvait créer recréer mes objet avec RequestBody

    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
     
    @RestController
    @RequestMapping("/personne")
    @CrossOrigin
    public class PersonneWebService {
    	private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(PersonneService.class);
    	@Autowired
    	private PersonneService personneService;
     
    	@GetMapping("/get{id}")
    	public ResponseEntity<Personne> getById(@RequestParam(required = true) Integer id) {
    		Optional<Personne> mayBePersonne = personneService.getById(id);
     
    		if (mayBePersonne.isPresent()) {
    			return new ResponseEntity<Personne>(mayBePersonne.get(), HttpStatus.FOUND);
    		} else {
    			return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
    		}
    	}
     
    	@GetMapping(value = "/getAll")
    	public ResponseEntity<List<Personne>> getAll() {
    		return new ResponseEntity<List<Personne>>(personneService.getAll(), HttpStatus.FOUND);
    	}
     
    	@PostMapping(value = "/create")
    	public HttpStatus save(@RequestParam(name = "nom", required = true) String nom,
    			@RequestParam(name = "prenom", required = true) String prenom) {
    		Personne personne = new Personne(nom, prenom);
     
    		personneService.save(personne);
     
    		return HttpStatus.CREATED;
     
    //			return HttpStatus.NOT_ACCEPTABLE;
    	}
     
    	@PostMapping(path = "consume", consumes="application/json")
    	@ResponseStatus(code = HttpStatus.CREATED)
    	public void saveJSON(@RequestBody Personne personne) {
    LOGGER.debug("Personne founf : " + personne, null, personne, personne, personne, personne, personne, personne, personne, personne);
     
    		personneService.save(personne);
    	}
     
    	/*
    	@PostMapping(path = "/consumeAll", consumes = "application/json")
    //	@ResponseStatus(code = HttpStatus.CREATED)
    	public HttpStatus saveAllJSON(@RequestBody List<Personne> personnes) {
    LOGGER.debug("Personne founf : " + personnes.size());
     
    		personneService.saveAll(personnes);
     
    		return HttpStatus.CREATED;
    	}
     
     
    	@DeleteMapping(value = "/delete")
    	public HttpStatus delete(@RequestParam(value = "id", required = true) int id) {
    		Optional<Personne> mayBePersonne = personneService.getById(id);
     
    		if (mayBePersonne.isPresent()) {
    			personneService.delete(mayBePersonne.get());
     
    			return HttpStatus.OK;
    		} else {
    			return HttpStatus.NOT_FOUND;
    		}
    	}
     
    }
    Cordialement
    Consultez mes articles sur l'accessibilité numérique :

    Comment rendre son application SWING accessible aux non voyants
    Créer des applications web accessibles à tous

    YES WE CAN BLANCHE !!!

    Rappelez-vous que Google est le plus grand aveugle d'Internet...
    Plus c'est accessible pour nous, plus c'est accessible pour lui,
    et meilleur sera votre score de référencement !

  4. #4
    Membre averti

    Profil pro
    Inscrit en
    janvier 2009
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : janvier 2009
    Messages : 230
    Points : 443
    Points
    443
    Billets dans le blog
    5
    Par défaut
    Comme je n'aime pas me répéter, sur mon projet perso, j'ai fait un template Method (c'est un Design pattern), et ça marche sans problème:

    https://bitbucket.org/philippegibaul...ontroller.java

    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
     
    package com.calculateur.warhammer.rest.controller;
     
    import java.util.List;
     
    import org.springframework.http.MediaType;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
     
    import com.calculateur.warhamer.service.contrat.IServiceAvecRecherche;
    import com.calculateur.warhammer.base.dto.ILibelleDTO;
    import com.calculateur.warhammer.base.exception.FunctionnalExeption;
    import com.calculateur.warhammer.base.exception.ServiceException;
    import com.calculateur.warhammer.dto.recherche.RechercheInService;
     
    /**
     * Template Méthode pour les controlleur avec recherche paramétrée
     * @author phili
     *
     * @param <D> Type de DTO
     * @param <S> Type de Service
     */
    public abstract class AbstractListAvecRechercheRestController<D extends ILibelleDTO,S extends IServiceAvecRecherche<D>> extends AbstractListRestController<D, S>{
     
    	@PostMapping(value = "/parRecherche", consumes = MediaType.APPLICATION_JSON_VALUE,produces = MediaType.APPLICATION_JSON_VALUE)
    	public ResponseEntity<List<D>> getByRecherche(@RequestBody RechercheInService recherche)throws ServiceException,FunctionnalExeption{
    		return ResponseEntity.ok(getService().listeAvecParametresRecherche(recherche));
    	}
    }
    Par contre, pour ton get, je pense qu'il y a peut être un problème.

    Remplace:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @GetMapping("/get{id}")
    Par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @GetMapping("/get/{id}")

  5. #5
    Membre averti

    Profil pro
    Inscrit en
    janvier 2009
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : janvier 2009
    Messages : 230
    Points : 443
    Points
    443
    Billets dans le blog
    5
    Par défaut
    Par contre, et en fait, c'est ça le sens de ma remarque précédente, évite de mélanger le JSON avec @Entity.


    @Entity, c'est pour la base de données. Json, c'est dans la DTO, c'est ce que tu transferts vers l'extérieure.

    Et la DTO marche sans @JsonProperty("nom").

    Cordialement.

Discussions similaires

  1. Prise en main de JSON avec GWT
    Par GroXx dans le forum GWT et Vaadin
    Réponses: 5
    Dernier message: 05/02/2009, 13h47
  2. [POO] parcourir un objet json avec une boucle for in
    Par bucheron007 dans le forum Général JavaScript
    Réponses: 13
    Dernier message: 19/01/2009, 13h55
  3. Création de fichier json avec PHP
    Par versus68 dans le forum Langage
    Réponses: 1
    Dernier message: 02/06/2008, 12h56
  4. Consommation mémoire hallucinante avec glob()
    Par mobscene dans le forum Langage
    Réponses: 8
    Dernier message: 24/01/2007, 19h29
  5. [AJAX] Récupération d'un fichier JSON avec javaScript
    Par guerin dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 26/11/2006, 20h05

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