Implémentation de services web REST avec le framework Spring

REST (Representational State Transfer) ou RESTful est un style d’architecture reposant sur l’utilisation du protocole HTTP en tirant partie de son enveloppe et de ses en-tête sans ajout de surcouche. Ce paradigme d’architecture se veut parfaitement stateless et laisse donc le soin au client de gérer les sessions.

Dans cette article, j’expliquerai comment implémenter des services web de type REST avec le framework Spring. Le support de REST a été introduit à partir de la version 3 de Spring et il est basé sur Spring MVC. Cet article vous guidera étape par étape et vous permettra de mettre en place rapidement ce type de service avec Spring MVC.

Technologies utilisées

Pour cet exemple  d’implémentation de service REST j’utiliserai les technologies suivantes :

  • Spring MVC 3.1
  • Maven 3.1
  • Tomcat 7
  • Java 1.6

 

Nous poserons comme pré requis que le lecteur dispose d’un minimum de connaissances dans ces technologies. Pour vous aider à bien commencer ce nouveau je mettrais à disposition les sources du projet sur mon GitHub et elles pourront être importée dans Spring Tool Suite ou Eclipse.

Création du squelette du projet

 

Nous commencerons par créer un projet Spring web avec Spring Tool Suite. il est également possible d’utilier un archetype Maven ou Spring Roo pour générer la structure de base du projet. Etant donné la simplicité du projet il peut également être créé manuellement.

Voici la description des principaux composants du  projet :

  • src/main/java – ce répertoire contiendra toutes les sources  Java de notre projet. Cela inclue les controllers MVC qui procèderont aux requêtes REST requests et les éléments dont nous parlerons plus tard.
  • src/main/resources  – ce répertoire contiendra toutes les ressources de notre projet . Il peut conternir les fichiers de configuration dans une application d’entreprise mais dans le cas de notre exemple il contiendra juste le fichier de configuration de log4j.
  • META-INF/context.xml – Ce fichier contient les ressources utilisé par Tomcat au démarage. Ce fichier est vide dans le cas de notre exemple mais dans une application d’entreprise il contiendrait les références JNDI aux nombreuses ressouces de l’entreprise (data sources, MQ managers etc)
  • rest-services-config.xml – Ce fichier contient les definitions des différent Spring beans requis par notre application.
  • Web.xml – Ce fichier est la configuration pour notre application web java et il est requis comme une part du standard de la spécification des Servlet Java.
  • Pom.xml – C’est configuration Maven il contient les dépendances (external libraries) et construit une archive WAR déployable.

 

Figure 1.0 – Structure du projet

Une fois le squeltte de l’application de base est en place, il est nécessaire de configurer l’application. Nous commencer par le fichier Web.xml qui est présenté ci dessous. J’ai commenté chaque partie du fichier afin d’en expliquer le contenu.

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">

	<display-name>REST Sample</display-name>

	<!-- Main configuration file for this Spring web application. -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
/WEB-INF/config/rest-services-config.xml
</param-value>
	</context-param>

	<!-- Loads the Spring web application context using the config file defined 
		above. -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Define the Spring Dispatcher Servlet for the REST services. The 'contextConfiguration' 
		param with an empty value means that the Spring Context won't try to load 
		a default file called restservices-servlet.xml -->
	<servlet>
		<servlet-name>restservices</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value></param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- This Servlet mapping means that this Servlet will handle all incoming 
		requests -->
	<servlet-mapping>
		<servlet-name>restservices</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

 

 

Puis nous configurerons le fichier rest-services-config.xml . Chaque section est commentée afin d’expliquer son impact sur l’application.

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oxm="http://www.springframework.org/schema/oxm"
	xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
							http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
							http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
							http://www.springframework.org/schema/oxm
							http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd
							http://www.springframework.org/schema/util
  							http://www.springframework.org/schema/util/spring-util-3.0.xsd">

	<!-- Enables automatic mapping of fund objects to and from JSON -->
	<mvc:annotation-driven />

	<!-- Setup spring to pull in @Controller, @RequestMapping, etc Configuration 
		scans specified packages for classes configured as Spring managed beans and 
		automatically sets up objects annotated with @Controller, @Service etc. -->
	<context:component-scan base-package="com.blog.samples.webservices.rest" />
	<context:component-scan base-package="com.blog.samples.services" />

	<!-- TODO -->
	<bean
		class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

	<!-- Configures view for returning JSON to the client -->
	<bean
		class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
		<property name="contentType" value="text/plain" />
	</bean>

	<!-- TODO -->
	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<property name="messageConverters">
			<util:list id="beanList">
				<ref bean="jsonMessageConverter" />
			</util:list>
		</property>
	</bean>

	<!-- Converts JSON to POJO and vice versa -->
	<bean id="jsonMessageConverter"
		class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />

</beans>

 

La dernière partie de notre squelette d’application est le fichier maven POM file. Il contient les dépendances et les plugin utilisés :

 

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
							 http://maven.apache.org/maven-v4_0_0.xsd">
	<artifactId>rest-sample</artifactId>
	<modelVersion>4.0.0</modelVersion>
	<inceptionYear>2011</inceptionYear>
	<packaging>war</packaging>
	<groupId>com.blog.rest</groupId>
	<version>1.0</version>
	<properties>
		<releaseCandidate>1</releaseCandidate>
		<spring.version>3.1.1.RELEASE</spring.version>
		<java.version>1.5</java.version>
		<jackson.mapper.version>1.5.6</jackson.mapper.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<maven.javadoc.reporting.version>2.7</maven.javadoc.reporting.version>
		<commons.logging.version>1.1.1</commons.logging.version>
		<log4j.version>1.2.16</log4j.version>
		<context.path>rest-sample</context.path>
		<jackson.mapper.version>1.5.6</jackson.mapper.version>
	</properties>
	<build>
		<resources>
			<resource>
				<directory>src/main/resources</directory>
				<filtering>true</filtering>
			</resource>
		</resources>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<configuration>
					<warName>${context.path}</warName>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-asm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>${jackson.mapper.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.4</version>
		</dependency>
	</dependencies>
</project>

 

Arrivé à cette étape vous devez avoir le workspace de la  figure 1.0.

Définition des objets du domaine

Cet exemple d’application expose une serie de méthodes RESTful qui permettent à des applications clientes de réaliser des opérations sur des fonds ( en anglais Fund). Notre objet Fund est un  POJO très simple et il est défini de la façon suivante.

 

package com.blog.samples.domain;

import java.util.Date;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import com.blog.samples.web.utils.DateSerializer;

/**
 * The Class Fund.
 */
public class Fund {

	private String fundId;
	private String fundDescription;
	private double bidPrice;
	private double offerPrice;
	private Date lastUpdated;

	public Fund() {
	}

	/**
	 * Gets the fund id.
	 * 
	 * @return the fund id
	 */
	public String getFundId() {
		return fundId;
	}

	/**
	 * Sets the fund id.
	 * 
	 * @param fundId
	 *            the new fund id
	 */
	public void setFundId(String fundId) {
		this.fundId = fundId;
	}

	/**
	 * Gets the fund description.
	 * 
	 * @return the fund description
	 */
	public Object getFundDescription() {
		return fundDescription;
	}

	/**
	 * Sets the fund description.
	 * 
	 * @param fundDescription
	 *            the new fund description
	 */
	public void setFundDescription(String fundDescription) {
		this.fundDescription = fundDescription;
	}

	/**
	 * Gets the bid price.
	 * 
	 * @return the bid price
	 */
	public double getBidPrice() {
		return bidPrice;
	}

	/**
	 * Sets the bid price.
	 * 
	 * @param bidPrice
	 *            the new bid price
	 */
	public void setBidPrice(double bidPrice) {
		this.bidPrice = bidPrice;
	}

	/**
	 * Gets the offer price.
	 * 
	 * @return the offer price
	 */
	public double getOfferPrice() {
		return offerPrice;
	}

	/**
	 * Sets the offer price.
	 * 
	 * @param offerPrice
	 *            the new offer price
	 */
	public void setOfferPrice(double offerPrice) {
		this.offerPrice = offerPrice;
	}

	/**
	 * Gets the last updated.
	 * 
	 * @return the last updated
	 */
	@JsonSerialize(using = DateSerializer.class)
	public Date getLastUpdated() {
		return lastUpdated;
	}

	/**
	 * Sets the last updated.
	 * 
	 * @param lastUpdated
	 *            the new last updated
	 */
	public void setLastUpdated(Date lastUpdated) {
		this.lastUpdated = lastUpdated;
	}

	@Override
	public String toString() {
		return "Fund [fundId=" + fundId + ", fundDescription="
				+ fundDescription + ", bidPrice=" + bidPrice + ", offerPrice="
				+ offerPrice + ", lastUpdated=" + lastUpdated + "]";
	}
}

 

C’est une classe très simple et le seul point difficile est l’annotation @JsonSerialize(using=DateSerializer.class)  sur la méthodegetLastUpdated . Cette annotation permet de s’assurer que les dates Java  sont converties dans un format de date JSON date avant d’être retrournées au client. La classe DateDeserializer reférencé dans l’annotation permmettant d’assurer la conversion est définie de la façon suivante.

package com.blog.samples.web.utils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;

/**
 * The Class DateSerializer.
 */
public class DateSerializer extends JsonSerializer<Date> {

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.codehaus.jackson.map.JsonSerializer#serialize(java.lang.Object,
	 * org.codehaus.jackson.JsonGenerator,
	 * org.codehaus.jackson.map.SerializerProvider)
	 */
	@Override
	public void serialize(Date value_p, JsonGenerator gen,
			SerializerProvider prov_p) throws IOException,
			JsonProcessingException {
		SimpleDateFormat formatter = new SimpleDateFormat(
				"yyyy-MM-dd'T'HH:mm:ss");
		String formattedDate = formatter.format(value_p);
		gen.writeString(formattedDate);
	}
}

 

 

Définition des opérations REST

 

Puis nous créerons un controller et définirons les méthodes RESTful que nous souhaitons exposer au client.

 

Obtenir un fond – HTTP GET

 

/**
	 * Gets a fund by fund id.
	 *
	 * @param fundId_p
	 *            the fund id_p
	 * @return the fund
	 */
	@RequestMapping(value = "/rest/funds/{fundId}", method = RequestMethod.GET)
	public ModelAndView getFund(@PathVariable("fundId") String fundId_p) {
		Fund fund = null;

		/* validate fund Id parameter */
		if (isEmpty(fundId_p) || fundId_p.length() < 5) {
			String sMessage = "Error invoking getFund - Invalid fund Id parameter";
			return createErrorResponse(sMessage);
		}

		try {
			fund = fundService_i.getFundById(fundId_p);
		} catch (Exception e) {
			String sMessage = "Error invoking getFund. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}

		logger_c.debug("Returing Fund: " + fund.toString());
		return new ModelAndView(jsonView_i, DATA_FIELD, fund);
	}

 

 

Ligne  1 – L’annotation RequestMapping permet de s’assurer que la requête HTTP pour  /rest/funds/{fundId} sera routé par cette méthode. method = RequestMethod.GET s’assure que seulement la requête HTTP GET sont utilisé par cette méthode.

Ligne 2 – @PathVariable est une façon commode spécifier une valeur en dehors de l’URL(ex: fundId) et de l’assigner aux paramètres de la méthode.

Lignes 6 to 9 – Permet de validé le format du Fund id. Si il n’est pas valide une réponse en erreur est retournée avec le message correpondant.

Lignes 11 to 16 –C’est simplement l’appel à notre service pour obtenir les informations sur le fond concerné.
Ligne 19 – Création d’un objet ModelAndView object using the JSON view and our fund object. We defined a MappingJacksonJsonView in rest-services-config earlier. This is used to convert the Fund object to JSON before it is returned to the client.

 

Création d’un Fond – HTTP POST

 

	/**
	 * Creates a new fund.
	 *
	 * @param fund_p
	 *            the fund_p
	 * @return the model and view
	 */
	@RequestMapping(value = { "/rest/funds/" }, method = { RequestMethod.POST })
	public ModelAndView createFund(@RequestBody Fund fund_p,
			HttpServletResponse httpResponse_p, WebRequest request_p) {

		Fund createdFund;
		logger_c.debug("Creating Fund: " + fund_p.toString());

		try {
			createdFund = fundService_i.createFund(fund_p);
		} catch (Exception e) {
			String sMessage = "Error creating new fund. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}

		/* set HTTP response code */
		httpResponse_p.setStatus(HttpStatus.CREATED.value());

		/* set location of created resource */
		httpResponse_p.setHeader("Location", request_p.getContextPath() + "/rest/funds/" + fund_p.getFundId());

		/**
		 * Return the view
		 */
		return new ModelAndView(jsonView_i, DATA_FIELD, createdFund);
	}

 

Ligne 1 – utilisation de l’annotation RequestMapping pour utiliser la requêtes HTTP  pour /rest/funds/ qui sera routée par cette méthode . Elle diffère de la requête  précédente pour l’utilisation d’une requête HTTP POST spécifiée avec la partie method = RequestMethod.POST.

Line 2 – L’annotation @RequestBody prend le contenu de la requête HTTP et le convertis en un objet Fund. La requête HTTP doit contenir la donnée Fund dans une forme valide de donnée JSON . Nous verrons plus tard comment la requête est configurée côté client. L’objet HTTPResponse est exposé par Spring MVC comme un moyen de configurer la réponse- this is described below.

Lines 8 to 13 – ici est appelé le service pour créer un nouveau fund. Dans notre application aucune action n’est réalisé mais dans une véritable application ce serait le moment de persister un nouveau  Fund.

Nous utiliserons des principes identiques pour créer les deux requête suivantes :

 

Mettre à jour un fond – HTTP PUT

 

	/**
	 * Updates fund with given fund id.
	 *
	 * @param fund_p
	 *            the fund_p
	 * @return the model and view
	 */
	@RequestMapping(value = { "/rest/funds/{fundId}" }, method = { RequestMethod.PUT })
	public ModelAndView updateFund(@RequestBody Fund fund_p, @PathVariable("fundId") String fundId_p,
								   HttpServletResponse httpResponse_p) {

		logger_c.debug("Updating Fund: " + fund_p.toString());

		/* validate fund Id parameter */
		if (isEmpty(fundId_p) || fundId_p.length() < 5) {
			String sMessage = "Error updating fund - Invalid fund Id parameter";
			return createErrorResponse(sMessage);
		}

		Fund fund = null;

		try {
			fund = fundService_i.updateFund(fund_p);
		} catch (Exception e) {
			String sMessage = "Error updating fund. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}

		httpResponse_p.setStatus(HttpStatus.OK.value());
		return new ModelAndView(jsonView_i, DATA_FIELD, fund);
	}

 

Supprimer un fond – HTTP DELETE

 

	/**
	 * Deletes the fund with the given fund id.
	 *
	 * @param fundId_p
	 *            the fund id_p
	 * @return the model and view
	 */
	@RequestMapping(value = "/rest/funds/{fundId}", method = RequestMethod.DELETE)
	public ModelAndView removeFund(@PathVariable("fundId") String fundId_p,
								   HttpServletResponse httpResponse_p) {

		logger_c.debug("Deleting Fund Id: " + fundId_p.toString());

		/* validate fund Id parameter */
		if (isEmpty(fundId_p) || fundId_p.length() < 5) {
			String sMessage = "Error deleting fund - Invalid fund Id parameter";
			return createErrorResponse(sMessage);
		}

		try {
			fundService_i.deleteFund(fundId_p);
		} catch (Exception e) {
			String sMessage = "Error invoking getFunds. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}

		httpResponse_p.setStatus(HttpStatus.OK.value());
		return new ModelAndView(jsonView_i, DATA_FIELD, null);
	}

	public static boolean isEmpty(String s_p) {
		return (null == s_p) || s_p.trim().length() == 0;
	}

 

 

Le service : FundService

 

Notre FundService expose un certain de méthodes qui sont applées par les methodes définies précédemment. C’est un service très simple et ne fait rien d’autre que de retourner des données “codées en dure” . Dans une application réelle un service devrait utiliser un DAO pour réaliser des opérations sur la base de données correspondant aux requêtes utilisées.

 

package com.blog.samples.services;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.blog.samples.domain.Fund;

/**
 * The Class FundService.
 */
@Service
public class FundService {

	private static final Logger logger_c = Logger.getLogger(FundService.class);

	/**
	 * Get the fund by id.
	 *
	 * @param fundId_p
	 *            the fund id_p
	 * @return the fund by id
	 */
	public Fund getFundById(String fundId_p) {
		Fund fund = new Fund();

		fund.setFundId(fundId_p);
		fund.setFundDescription("High Risk Equity Fund");
		fund.setBidPrice(26.80);
		fund.setOfferPrice(27.40);
		fund.setLastUpdated(new Date());

		return fund;
	}

	/**
	 * Gets all funds.
	 *
	 * @return the all funds
	 */
	public List<Fund> getAllFunds() {
		List<Fund> funds = new ArrayList<Fund>();

		for (int i = 0; i < 10; i++) {
			Fund fund = new Fund();

			fund.setFundId("12345" + i);
			fund.setFundDescription("High Risk Equity Fund " + (i + 1));
			fund.setBidPrice(26.80 + (Math.random() * 10));
			fund.setOfferPrice(27.40 + (Math.random() * 10));
			fund.setLastUpdated(new Date());

			funds.add(fund);
		}

		return funds;
	}

	/**
	 * Creates the fund.
	 *
	 * @param fund_p
	 *            the fund_p
	 * @return the fund
	 */
	public Fund createFund(Fund fund_p) {

		logger_c.debug("Persisting fund in database: " + fund_p.toString());

		/* set id and timestamp */
		fund_p.setFundId("12345");
		fund_p.setLastUpdated(new Date());

		return fund_p;
	}

	/**
	 * Update fund.
	 *
	 * @param fund_p
	 *            the fund_p
	 * @return the fund
	 */
	public Fund updateFund(Fund fund_p) {

		logger_c.debug("Updating fund in database: " + fund_p.toString());

		/* set timestamp */
		fund_p.setLastUpdated(new Date());

		return fund_p;
	}

	/**
	 * Delete fund.
	 *
	 * @param fundId_p
	 *            the fund id_p
	 */
	public void deleteFund(String fundId_p) {
		logger_c.debug("Deleting fund from database: " + fundId_p.toString());

	}

}

 

Lancer l’Application

Notre application est terminé nous pouvons maintenant faire un Build et la déployer. J’ai lancé cette application sur Tomcat mais elle peut être lancer sur un autre Servlet container. Si vous ne souhaitez pas construire cette application étape par étape, il est possible de récupérer les sources sur mon GitHub, construire l’archive WAR et la déposer sur votre server.

 

 

Tester l’application avec RESTClient sur Firefox

 

Il y a de nombreux frameworks disponibles pour vous permettre de construire rapidement un client RESTful. Pour garder cet article le plus simple possible j’ai opté pour tester cette application le plugin firefox RESTClient pour Firefox que l’on peut télécharger à l’adresse suivante :

https://addons.mozilla.org/fr/firefox/addon/restclient/

Une fois installer on peut tester tout les endpoint RESTful définis précédemment.

 

Test GET fund

Nous commençerons par obtenir un  fond spécifique .La  figure 2.0 ci dessous nous montre l’envoie d’une requête GET pour  http://localhost:8080/rest-sample/rest/funds pour un fund id = 12345.  Le code réponse HTTP   (200 OK) et la réponse JSON retournée par le server est la suivante.

image

Figure 2.0 – Test HTTP GET

 

Conclusion

Cet article vous montre comment construire des services RESTful utilisant le framework Spring Cette application est assez triviale mais elle permet d’avoir les bases pour développer des services REST.

Vous pouvez récupérer les sources de ce projet sur mon GitHub :

https://github.com/jyjeanne/rest-sample

18 février 2014

0 responses on "Implémentation de services web REST avec le framework Spring"

Leave a Message

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

© WayofCode. All rights reserved.

Setup Menus in Admin Panel