Crear aplicaciones con MongoDB, Spark y FreeMarker

En este artículo se va ver cómo crear aplicaciones con MongoDB, Spark y FreeMarker totalmente integrados. La aplicación de ejemplo será muy simple pero lo suficientemente completa como para entender como interactúan estas tres tecnologías juntas y tener una base para el desarrollo del blog de este tutorial de MongoDB con Java. Como ya sabrán, el IDE que se usa es IntelliJ.

Las clases usadas en este ejemplo serán simples y sencillas, por lo que los datos de acceso o de cualquier otra clase estarán definidos de forma interna (una forma poco recomendable en la realidad). Se recomienda antes de seguir la lectura de los artículos anteriores para tener todo correctamente instalado y configurado.

Conexión con MongoDB

Instalación de MongoDBEl primer paso va a ser crear una clase para conectarse con la base de datos NoSQL MongoDB. Esta clase crea una conexión cliente contra la base de datos por defecto “localhost:27017”, usando la base de datos “course” y, dentro de esta, la colección “hello” dónde se tendrán los documentos para ser consultados.

package es.happyminds;

import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;

import java.net.UnknownHostException;

/**
 * Created by Happy Minds! Software
 * URL: http://www.happyminds.es
 * Tutorial: Blog using MongoDB, Spark and FreeMarker
 */
public class MongoDB {

    private static final String HOST = "localhost";
    private static final int PORT = 27017;
    private static final String DB_NAME = "course";
    private static final String DB_COLLECTION = "hello";

    private MongoClient client;
    private DB database;
    private DBCollection collection;

    /**
     * Constructor create a client database pool connections     *
     * @throws UnknownHostException
     */
    public MongoDB() throws UnknownHostException {
        this.client = new MongoClient(HOST, PORT);
        this.database = client.getDB(DB_NAME);
        this.collection = database.getCollection(DB_COLLECTION);
    }

    /**
     * @return Any document
     */
    public DBObject getOneDocument() {
        return collection.findOne();
    }
}

La clase MongoClient define internamente un pool de conexiones, el cual puede ser configurado según se desee, y se conecta con la base de datos (en este caso no hace falta autenticación). Puede lanzar una excepción del tipo UnknownHostException si no encuentra el host para conectarse.

Al obtener la base de datos (getDB) sino existe la crea o, en otro caso, la marca para ser usada. Lo mismo se puede aplicar a la colección.

Plantillas HTML con FreeMarker

FreeMarkerPara guardas las plantillas se va a crear una carpeta llamada “resources” que estará ubicada a la misma altura que la carpeta “java” que contiene el código fuente, es decir, en “src/main” de nuestro proyecto.

En este caso se han creado dos plantillas FreeMarker:

hello.ftl” para mostrar el valor de la clave “name” del documento extraído de la base de datos mediante la variable homónima ${name}.

<html>
<head>
    <title>Happy Minds Wellcome!</title>

</head>
<body>
    <h1>Hello ${name}</h1>
</body>
</html>

colors.ftl” para mostrar un formulario con una lista de colores. La lista de colores se establece en la plantilla desde “Spark” con el nombre “colors” y se usa la utilidad “list” de FreeMarker para recorrer dicha lista e ir insertando las distintas opciones.

<html>
<head>
    <title>Happy Minds Colors Picker</title>
</head>
<body>

<form action="/favorite_color" method="POST">

    <p>What is your favorite color?</p>
    <#list colors as color>
        <p><input type="radio" name="color" value="${color}"> ${color}</input></p>
    </#list>
    <input type="submit" value="Submit"/>
</form>

</body>
</html>

Manejador de rutas con Spark

SparkEl siguiente paso es crear el manejador de rutas con Spark. Esta clase se encargará principalmente de ejecutar la lógica de negocio correspondiente a cada ruta definida. De este modo, Spark junto con el contenedor de Servlets Jetty que tiene embebido,  detecta el tipo de petición HTTP (GET, POST…) y la ruta que es invocada para actuar en consecuencia.

package es.happyminds;

import freemarker.template.Configuration;
import freemarker.template.Template;
import spark.Request;
import spark.Response;
import spark.Route;
import spark.Spark;

import java.io.StringWriter;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Happy Minds! Software
 * URL: http://www.happyminds.es
 * Tutorial: Blog using MongoDB, Spark and FreeMarker
 */
public class SparkExample {

    private Configuration configuration;
    private MongoDB database;

    /**
     * Get a MongoDB client connection and load the FreeMarker template.
     * @throws UnknownHostException
     */
    public SparkExample() throws UnknownHostException {
        this.configuration = new Configuration();
        configuration.setClassForTemplateLoading(SparkExample.class, "/");
        database = new MongoDB();
    }

    public void start() {

        Spark.get(new Route("/") {
            @Override
            public Object handle(Request request, Response response) {
                return "Hello World!";
            }
        });

        Spark.get(new Route("/test") {
            @Override
            public Object handle(Request request, Response response) {
                return "Hello World Test Page!";
            }
        });

        Spark.get(new Route("/echo/:message") {
            @Override
            public Object handle(Request request, Response response) {
                return request.params(":message");
            }
        });

        Spark.get(new Route("/hellodb") {
            @Override
            public Object handle(Request request, Response response) {
                StringWriter writer = new StringWriter();
                try {

                    Template hello = configuration.getTemplate("hello.ftl");
                    hello.process(database.getOneDocument(), writer);

                } catch (Exception e) {
                    halt(500);
                    e.printStackTrace();
                }
                return writer;
            }
        });

        Spark.get(new Route("/colors_form") {
            @Override
            public Object handle(Request request, Response response) {
                StringWriter writer = new StringWriter();
                try {
                    Template hello = configuration.getTemplate("colors.ftl");

                    Map<String, Object> colors = new HashMap<String, Object>();
                    colors.put("colors", Arrays.asList("Blue", "Black", "White", "Yellow", "Orange", "Red"));

                    hello.process(colors, writer);

                } catch (Exception e) {
                    halt(500);
                    e.printStackTrace();
                }
                return writer;
            }
        });

        Spark.post(new Route("/favorite_color") {
            @Override
            public Object handle(Request request, Response response) {
                final String fruit = request.queryParams("color");
                if (fruit == null) {
                    return "Why don't you pick one?";
                } else {
                    return "Your favorite color is " + fruit;
                }
            }
        });
    }
}

Como se puede ver, se define el acceso a la platilla con Template y posteriormente, con el método process, se establecen las variables. Este proceso buscará las variables especificadas en la plantilla y las sustituirá por el valor que contiene en el objeto pasado. A continuación se explica lo que realiza cada manejador definido cuando es invocado a la vez que se muestra el resultado esperado.

“/”: GET. Referencia al index. Retorna la cadena de caracteres “Hello World!”

“/test”: GET. Referencia a una página denominada “test”. Simplemente retorna la cadena “Hello World Test Page!”

“/echo/:message”: Captura el valor de la variable “message” (los “:” definen la variable) y retorna su contenido.

“/hellodb”: Esta página solicita a la base de datos MongoDB un documento cualquiera, Se recoge el valor de la clave “name” del documento y se establece dicho valor en la plantilla “hello.ftl” mediante la variable ${name}. En el apartado siguiente se insertará en MongoDB un documento para poder ejecutar este caso.

“/colors_form”: GET. Muestra un formulario que pregunta por su color favorito. Para ello, carga una lista de colores predeterminada que será especificada en la plantilla “colors.ftl”. Al pulsar sobre el botón “Submit” enviará el color indicado, mediante el método POST, a “/favorite_color”.

“/favorite_color”: POST. Recibe el color seleccionado en el formulario “colors_form” y devuelve un texto indicando dicho color. En caso de enviar el formulario sin seleccionar un color se mostrará un mensaje incitando a hacerlo.

Ejecutando el ejemplo

Antes de nada, se va a insertar en la base de datos un documento para el caso en el que se solicita un documento a dicha base de datos para mostrar el valor de la clave “name”. Por tanto, nos conectamos en la shell cliente de MongoDB:

$ mongo

MongoDB shell version: 2.2.3
connecting to: test

y posteriormente añadimos un documento:

> use course
switched to db course
> db.hello.save( { "name": "MongoDB student!"} )

Probamos que se ha insertado correctamente:

> db.hello.findOne()
{ "_id" : ObjectId("5137b0bff51ebf094123aa4c"), "name" : "MongoDB student!" }

Ahora, arrancamos la aplicación desde IntelliJ seleccionando la clase SparkExample y ejecutando “Run” o “debug”. Una vez hecho esto el servidor estará levantado y escuchando en el puerto por defecto:

== Spark has ignited ...
>> Listening on 0.0.0.0:4567

Y por último se prueba la aplicación insertando en un navegador las rutas definidas usando Spark.

http://localhost:4567/

http://localhost:4567/test

http://localhost:4567/echo/caracola

http://localhost:4567/hellodb

http://localhost:4567/colors_form

Resultado, después de “Submit”, seleccionando un color:

Resultado, después de “Submit”, no seleccionando un color:

Espero que todo haya funcionado correctamente y se haya entendido a la perfección cómo crear aplicaciones con MongoDB, Spark y FreeMarker además de ir cogiendo una idea del funcionamiento de estas tecnologías.

Como siempre, para cualquier duda o sugerencia dejad un comentario.

Happy Minds!!!

Share on FacebookTweet about this on TwitterShare on LinkedInShare on RedditShare on Google+Digg thisShare on TumblrPin on PinterestBuffer this pagePrint this pageEmail this to someone