El codigo esta en el GitHub:
https://github.com/cyberglad/kotlindemo
Este servicio simplemente nos va decir "Hola, <tu nombre>". Al inicio no necesitamos mas. Pero solo al inicio. No vas a poner en tu currículum un servicio "Hola mundo!", entonces enseguida lo vamos a hacer mas inteligente y redirigir las respuestas según que parametro le pasas.
Kotlin - un lenguaje de la familla Java, pero mas "pragmático", breve y conciso y se parece un poco a Groovy. Que por supuesto también utiliza la JVM.
IntelliJ IDEA - hace poco que descubierto esta IDE y estoy encantado, especialmente me encanta la integration con Kotlin (normal, visto que las 2 cosas pertenecen a la misma sociedad - JetBrains). Os recomiendo mucho: tiene muy buen "texto predictivo" (por fin he encontrado uno que tiene sentido) casi como MS Visual Studio y mucho mejor que Eclipse. También el entorno es muy claro, los "pom.xml" de Maven por fin se ven bien estructurados.
Spring Boot - pa alegrarnos la vida y no enrollarnos con el Tomcat.
Spring Initializer (https://start.spring.io): para tener lista la estructura del proyecto Maven con el pom.xml
Kotlin + IntelliJ + Spring Boot = crea un entorno rápido y eficaz sin perder el tiempo en chorradas tipo "como crear mi proyecto Maven y importar todas las bibliotecas necesarias".
Creación del Proyecto
1) Utilizamos Spring Initializer que nos genera el proyecto Maven listo con su estructura (vamos a https://start.spring.io/)1) Seleccionamos "Maven" como proyecto, "Kotlin" como lenguaje y la versión Spring Boot 1.5.4 (tb he probado otras - funciona igual).
2) Como "dependencies" necesitaremos solo el Jersey JAX-RS
3) Ya esta! Venga, a descargar el proyecto! Lo guardamos en el folder, donde la IDEA guarda todos los proyectos - C:\Users\<tu nombre>\IdeaProjects, mira la captura e pantalla abajo..
Importación en IntelliJ IDEA
1) Instalamos la IDEA, la abrimos y vamos a "File->Open":
2) Simplemente seleccionamos la carpeta de nuestro proyecto y damos a "Ok".
3) Esperamos un poco para que la IDEA pueda importar todo y nos creara las carpetas "src" con "main" y "test"con la clase principal y donde vamos a meter nuestro código. Nota que la carpeta "main" contiene la carpeta "kotlin" en vez de "java".
4) En la carpeta "kotlin" encontramos nuestro paquete principal com.projects.kotlin.kotlindemo con la clase principal KotlindemoApplication que desde el inicio tiene buena pinta:
package com.projects.kotlin.kotlindemo import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication @SpringBootApplicationclass KotlindemoApplication fun main(args: Array<String>) { SpringApplication.run(KotlindemoApplication::class.java, *args) }
Que chulo este syntax, no? La manera de declarar el método con la palabra "fun" o variables con doble-punto! No hay ni "public", ni "static", ni punto y coma al final.
Creación del controlador
1) Lanzamos esta clase tal cual y con mucha alegría descubrimos que todo va bien, nuestro proyecto se compila sin errores y el Tomcat escucha a la puerta 8080 (miraremos en el log de Spring Boot):Tomcat started on port(s): 8080 (http)
2) Pero vamos a crear algo útil: creamos un paquete "restful" y el controlador Spring - una clase Kotlin GreetController(botón derecho del ratón->New->New Kotlin Class):
La clase la declaramos "open" y le ponemos 2 anotaciones: "@Component" (ALT+Enter para importar la biblioteca necesaria) para declarar un servicio y @Path("greet/{name}" (ALT+Enter para importar la biblioteca necesaria) para especificar el camino de acceso.
3) Luego creamos el método "greet" (con anotaciones correctas - @GET y @Produces para declarar que volveremos algo mas que una simple String):
@Component
@Path("greet/{name}") open class GreetController{ @GET
@Produces(MediaType.APPLICATION_JSON) fun greet(@PathParam("name") name:String): Response { return Response.ok(name).build() } }
4) Ahora creamos una clase de la configuración Jersey, sino Jersey no se sabe configurar correctamente. Para eso heredemos la clase JerseyConfig de la clase ResourceConfig:
import org.glassfish.jersey.server.ResourceConfig import org.springframework.stereotype.Component
@Component
class JerseyConfig: ResourceConfig { constructor() { packages(JerseyConfig:: class.java.`package`.name) } }
La declaramos "open", pq normalmente Kotlin hace las clases "cerradas" para el acceso externo.
Me hace gracia, como se crea el constructor (con la palabra "constructor", sino como?)!
JerseyConfig:: class.java.`package`.name
Lo que en Java se hubiera hecho con JerseyConfig.class, aqui se hace con JerseyConfig:: class.java
Luego sacamos el "package" con la palabra "package", y, como en Kotlin esta "reservada", le ponemos las comillas. Al final ponemos el nombre.del package (en Java eso se hacía con .getPackage()).
Lanzamiento
1) Voila! lanzaremos este servicio para ver nuestro nombre. El lanzamiento se hace en Intellij IDEA en 2 maneras:2) Si no hay nada rojo en el log de la aplicación, la ultima frase nos dice que la aplicación esta lanzada:
Started KotlindemoApplicationKt in 5.216 seconds (JVM running for 6.136)
Iremos en nuestro browser a:
http://localhost:8080/greet/<escribe tu nombre>
Y aprovecha a ver una pagina blanca con tu nombre escrito. En mi caso es "Yuri":
Extras
Ahora vamos a hacer algo mas complicado:- evitamos que un nombre especifico ("R21", podía ser el nombre de un robot malo que quiere hackear nuestro servicio) vea lo que vuelve nuestro servicio. Cuando R21 intenta a acceder al servicio - tiene que ver un error, los demás - no.
- añadimos la fecha y hora al saludo
Mi servicio tiene que distinguir el usuario R21 de los demás. Como se realiza eso? Normalmente se crea una excepción, donde metemos la lista de los usuarios "malos". Nuestro servicio mira el parámetro del nombre y si el nombre corresponde al "nombre malo", le asigna esta excepción y le envia un mensaje de error.
Yo no quiero utilizar las excepciones y Kotlin me va ayudar en eso.
1) Creamos un nuevo paquete "service" donde metemos nuestro servicio (una nueva clase GreetService).
2) En esta clase creamos una interface Resp para la respuesta (la creamos directamente dentro la clase).
Dentro esta interface creamos 2 clases para 2 tipos de respuesta (Success y Error) que implementan la interface (mira que facil):
import org.springframework.stereotype.Component
@Component
class GreetService{ interface Resp { class Success(val msg: String): Resp class Error(): Resp } fun greet(name: String): Resp { return if (name.equals("R21")) Resp.Error() else
Resp.Success("Hello, ${name}") } }
También necesitaremos el método "greet" que acepta nuestro nombre y que va devolver la respuesta del tipo "Success" o del tipo "Error" (si el nombre es "R21").
3) Toca modificar también nuestro controlador:
package com.projects.kotlin.kotlindemo.restful import com.projects.kotlin.kotlindemo.service.GreetService import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Componentimport java.util.* import javax.ws.rs.GET import javax.ws.rs.Path
import javax.ws.rs.PathParamimport javax.ws.rs.Producesimport javax.ws.rs.core.MediaType import javax.ws.rs.core.Response @Component
@Path("greet/{name}") open class GreetResource @Autowired constructor(val service: GreetService){ data class Greet(val message: String, val time:String) @GET @Produces(MediaType.APPLICATION_JSON) fun greet(@PathParam("name") name:String): Response { val resp = service.greet(name) return when(resp){ is GreetService.Resp.Success -> Response.ok(resp.msg, Date().toString()).build() is GreetService.Resp.Error -> Response.status(Response.Status.BAD_REQUEST).build() else->Response.status(Response.Status.INTERNAL_SERVER_ERROR).build() } return Response.ok(name).build() } }
Explicación:
La primera linea es típica para Kotlin: la declaración de la case + inyección del servicio @Autowired +el constructor - todo en la misma linea a la vez!
Creamos nuestra respuesta:
val resp = service.greet(name)
y declaramos, si el usuario es "R21" - devolvemos el error, si es otro - un saludo + la fecha y la hora(y si otra cosa - Internal Server Error):
return when(resp){ is GreetService.Resp.Success -> Response.ok(resp.msg).build() is GreetService.Resp.Error -> Response.status(Response.Status.BAD_REQUEST).build() else->Response.status(Response.Status.INTERNAL_SERVER_ERROR).build() }
Metemos "R21" como nombre y veremos la pagina para el usuario "malo":
No hay comentarios:
Publicar un comentario