En este post se va a explicar cómo consumir un web service REST utilizando RestTemplate de Spring. Concretamente, se va a consumir los servicios proporcionados por http://freegeoip.net/{format}/{ip-address}, que devuelve la geolocalización de la dirección ip indicada en el parámetro ip-address, en el formato indicado en el parámetro format. Si no se indica el parámetro ip-address, devuelve los datos de la ip desde la que se hace la petición al web service. Los formatos en que se obtiene la información son xml, csv y json. Para cada uno de estos formatos, crearemos las correspondientes clases java y la información recibida la mapearemos en instancias de estas clases.
Los pasos que se van a seguir son:
- Crear un proyecto básico de Spring
- Adecuar el archivo pom.xml con las dependencias de JSON
- Test formato XML
- Test formato JSON
- Test formato CSV
Crear un proyecto básico de Spring
En primer lugar crearemos un proyecto Spring básico en el que al final definiremos una clase de testeo JUnit en donde haremos las llamadas al web service. Para crear el proyecto, en nuestro STS pincharemos en File > New > Spring Project. El nombre del proyecto será rest-template-demo y elegiremos como plantilla Simple Spring Maven, tal y como se muestra en la siguiente imagen:
Adecuar el archivo pom.xml con las dependencias de JSON
En el pom.xml que se genera automáticamente eliminaremos lo relativo a Hibernate, ya que no lo vamos a utilizar. Añadiremos lo necesario para las dependencias web services y de JSON. Las dependencias mencionadas se incluyen del siguiente modo:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Jackson JSON Mapper -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${jackson.version}</version>
</dependency>
La versión que vamos a utilizar de jackson es la 1.9.10
Test formato XML
Crearemos una clase GeoIPTest bajo src/test/java, en el paquete com.lostinsoftware.rest.client. En esta clase crearemos el método XMLTest, que es el que utilizaremos para testear la recepción de la información en formato XML y convertirla a un objeto java.
Como queremos recibir la información directamente en objetos java, primeramente, tenemos que crear las correspondientes clases. Para ello obtendremos un ejemplo de xml de la información recibida. A partir de este xml, generaremos su xsd, y de este xsd crearemos las clases java, con anotaciones JAXB2. JAXB2 es el que se encarga en última instancia de hacer las conversiones necesarias oxm, esto es, el marhsalling/unmarshalling entre información xml y objetos java.
Un ejemplo de información xml la podmos obtener simplemente ejecutando en un navagedor http://freegeoip.net/xml/. La información es similar a:
<Response>
<Ip>88.9.100.100</Ip>
<CountryCode>code</CountryCode>
<CountryName>Spain</CountryName>
<RegionCode>01</RegionCode>
<RegionName>region</RegionName>
<City>city</City>
<ZipCode>11111</ZipCode>
<Latitude>42.9999</Latitude>
<Longitude>-1.9999</Longitude>
<MetroCode>metro</MetroCode>
<AreaCode>area</AreaCode>
</Response>
A continuación, para obtener el xsd de este xml, nos apoyaremos en la herramienta XmlGrid.net. Iremos a la página http://xmlgrid.net/xml2xsd.html. La xsd obtenida es:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<!-- XML Schema Generated from XML Document on Thu Oct 17 2013 21:19:27
GMT+0100 (CET) -->
<!-- with XmlGrid.net Free Online Service http://xmlgrid.net -->
<xs:element name="Response">
<xs:complexType>
<xs:sequence>
<xs:element name="Ip" type="xs:string"></xs:element>
<xs:element name="CountryCode" type="xs:string"></xs:element>
<xs:element name="CountryName" type="xs:string"></xs:element>
<xs:element name="RegionCode" type="xs:int"></xs:element>
<xs:element name="RegionName" type="xs:string"></xs:element>
<xs:element name="City" type="xs:string"></xs:element>
<xs:element name="ZipCode" type="xs:int"></xs:element>
<xs:element name="Latitude" type="xs:double"></xs:element>
<xs:element name="Longitude" type="xs:double"></xs:element>
<xs:element name="MetroCode" type="xs:string"></xs:element>
<xs:element name="AreaCode" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
La primera línea correspondiente a la definición xml la añadimos nosotros para denotar que es un archivo xml. El xsd lo guardamos en archivo llamado geoipxml.xsd, bajo src/main/resources/schemas.
Para generar las clases java, a partir del xsd, utilizaremos la herramienta xjc. Crearemos un build ant. El contenido de este build, al que llamaremos create-classes.xml, y lo situaremos en el raíz del proyecto, es:
<?xml version="1.0"?>
<project name="geoipxml" default="generate-sources">
<property name="src.dir" value="src/main/java"/>
<property name="repository.dir" value="${basedir}/../../repository"/>
<target name="generate-sources">
<exec executable="xjc">
<arg line=" -d ${src.dir} -p com.lostinsoftware.rest.types src/main/resources/schemas/geoipxml.xsd"/>
</exec>
</target>
</project>
Ejecutaremos este archivo situando encima de él, pulsando seguidamente click-derecho y eligiendo Run As … > Ant Build. Tras la ejecución, al refrescar el directorio src/main/java, veremos que se ha creado un paquete con una serie de clases en su interior. Son clases con notación JAXB que se utilizarán en la comunicación con el web service. En este momento ya estamos en disposición de crear el método, llamado XMLTest, donde recibiremos la información de geoposicionamiento de una dirección IP en un objeto de clase Response que acabamos de crear.
@Test
public void XMLTest(){
RestTemplate restTemplate = new RestTemplate();
Response geoIPXml=null;
try {
geoIPXml = restTemplate.getForObject(new URI("http://freegeoip.net/xml") , Response.class);
} catch (RestClientException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
assertNotNull(geoIPXml);
}
Como se puede observar en el código, utilizamos un objeto restTemplate, mediante el cual utilizando el método genérico getForObject, hacemos la llamada a la url del servicio web REST, indicándole que queremos recibir la información en un objeto de clase Response.class.
Test formato JSON
Al igual que en el caso anterior, lo que haremos será crear una clase java que represente a los datos JSON recibidos del web service. Para crear la clase java a partir de un texto con formato JSON, utilizaremos la herramienta que se nos ofrece en http://www.jsonschema2pojo.org/. A partir de los datos en formato JSON obtenidos de http://freegeoip.net/json/ crearemos la clase java que represente dichos datos.
En la siguiente imagen podemos comprobar cómo generamos la clase java:
El código obtenido al pinchar en Preview lo guardaremos en una clase llamada GeoIPJson.java bajo el paquete com.lostinsoftware.rest.types. Se trata de una clase con getters y setters de los distintos elementos de información de la cadena JSON.
Seguidamente, creamos el método JSonTest, cuyo contenido es:
@Test
public void JSonTest(){
RestTemplate restTemplate = new RestTemplate();
List<httpmessageconverter<?>> messageConverters = new ArrayList<httpmessageconverter<?>>();
// Add the JSon Message converter
messageConverters.add(new MappingJacksonHttpMessageConverter());
GeoIPJson geoIPJson=null;
try {
geoIPJson = restTemplate.getForObject(new URI("http://freegeoip.net/json") , GeoIPJson.class);
} catch (RestClientException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
assertNotNull(geoIPJson);
}
En este caso al objeto restTempalete le añadimos el converter de Jackson, ya que por defecto sólo está el de XML.
El resto de código es similar al caso de la recepción de datos en formato XML.
Test formato CSV
En este test no tendremos que crear previamente ninguna clase ya que el web service REST devuelve una cadena, con valores separados por comas. Para este caso, únicamente nos preocuparemos de añadir el convertidor StringHttpMessageConverter para recibir la cadena mencionada. Creamos el método CSVTest con el siguiente contenido:
@Test
public void CSVTest(){
RestTemplate restTemplate = new RestTemplate();
List<httpmessageconverter<?>> messageConverters = new ArrayList<httpmessageconverter<?>>();
// Add the String Message converter
messageConverters.add(new StringHttpMessageConverter());
String geoIPcsv=null;
try {
geoIPcsv = restTemplate.getForObject(new URI("http://freegeoip.net/csv") , String.class);
} catch (RestClientException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
assertNotNull(geoIPcsv);
String[]] data = StringUtils.commaDelimitedListToStringArray(geoIPcsv);
assertTrue(data.length>1);
}
En el código cabe destacar la utilización de StringUtils para obtener por separado cada uno de los datos que el web service proporciona.
Los fuentes del proyecto se encuentran en el archivo rest-template-demo.zip
Post relacionados: