[JAVA] Einfacher Mikroservice mit Spark Framework!

1. Was ist Spark Framework?

Es ist ein sehr einfaches Webanwendungsframework, das auf der offiziellen Website (http://sparkjava.com/) wie folgt beschrieben wird:

Spark - A micro framework for creating web applications in Kotlin and Java 8 with minimal effort

Es hat eine Bewertung von: star: 7199 auf github (Stand: 04.03.2008), daher scheint es ein ziemlich genutztes Framework zu sein.

Als Feature ist es sehr einfach, eine Webanwendung mit Lambda-Ausdrücken und statischen Methoden zu implementieren. Unten finden Sie ein Beispiel aus der offiziellen Dokumentation.

HelloWorld.java


import static spark.Spark.*;

public class HelloWorld {
    public static void main(String[] args) {
        get("/hello", (req, res) -> "Hello World");
    }
}

Führen Sie es als normale Java-Anwendung mit einer Hauptmethode aus. Rufen Sie nach dem Start der Anwendung mit einem Webbrowser auf http: // localhost: 4567 / hello auf, und Sie sehen "Hello World". Es ist sehr einfach! Dieses Mal möchte ich mit diesem Spark Framework eine Todo-App für den REST-Service erstellen.

2. Todo App-Spezifikationen

Todo.java


package com.example.spark.demo;

import java.io.Serializable;
import java.util.Date;

public class Todo implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private String todoId;
    private String todoTitle;
    private Date createdAt;
    private boolean finished;
    
    // constructor, setter, getter omitted
}
Artikelnummer Pfad HTTP-Methode Erläuterung
1 /api/todo POST Erstellen Sie ein TODO mit den übertragenen Daten
2 /api/todo/:todoId GET Ruft das von todoId angegebene TODO ab
3 /api/todo/:todoId PUT Aktualisieren Sie das von todoId angegebene TODO
4 /api/todo/:todoId DELETE Löschen Sie das von todoId angegebene TODO

2. Erstellen Sie ein Projekt

Erstellen Sie zunächst ein leeres Projekt mit mvn.

Befehlsbeispiel in Windows


mvn archetype:generate ^
-DinteractiveMode=false ^
-DarchetypeArtifactId=maven-archetype-quickstart ^
-DgroupId=com.example.spark.demo ^
-DartifactId=spark-demo

Fügen Sie nach dem Erstellen eines leeren Projekts die Bibliothek, die dieses Mal verwendet werden soll, zu "pom.xml" hinzu. Dieses Mal werden wir GSON verwenden, um das JSON-Format zu konvertieren. Andere Bibliotheken sind in Ordnung. Da das offizielle Dokument von Spark Framework GSON verwendet, habe ich mich dieses Mal für GSON entschieden.

pom.xml


    <!-- add spark framework -->
    <dependency>
      <groupId>com.sparkjava</groupId>
      <artifactId>spark-core</artifactId>
      <version>2.7.1</version>
    </dependency>
    <!-- add gson -->
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.8.2</version>
    </dependency>

Wenn das Hinzufügen der Bibliothek zu "pom.xml" abgeschlossen ist, wird die Bibliothek erfasst. Versuchen wir also, sie mit dem folgenden Befehl zu erstellen. Es ist in Ordnung, wenn "BUILD SUCCESS" angezeigt wird.

Befehl zum Erstellen einer Testversion


mvn package -Dmaven.test.skip=true

3. Quellcode

3.1. Anwendungsklasse

App.java


package com.example.spark.demo;

import static spark.Spark.*;

/**
 *★ Punkt 1
 * spark demo app
 */
public class App {
    //★ Punkt 1
    public static void main(String[] args) {
        //★ Punkt 2
        // initialize
        initialize();
        //★ Punkt 3
        // define api
        TodoApi.api();
        // omitted
    }

    //★ Punkt 2
    private static void initialize() {
        // server port
        port(8090);
        // static files
        staticFiles.location("/public");
        // connection pool
        // maxThreads, minThreads, timeOutMillis
        threadPool(8, 2, 30000);
    }
}

** ★ Punkt 1 ** Die Spark Framework-Anwendung wird als normale Java-Anwendung implementiert, die von der Main-Methode ausgeführt wird.

** ★ Punkt 2 ** Der Prozess der Initialisierung der Anwendung wurde auf die "Initialisierungs" -Methode reduziert. Dieses Mal habe ich die folgenden drei Anfangseinstellungen vorgenommen, die wahrscheinlich häufig verwendet werden.

Der Server-Port wurde mit der Methode "port" von "4567" auf "8090" geändert.

Es ist für einen normalen REST-Service nicht erforderlich, kann jedoch als einfacher Webserver verwendet werden. Daher werde ich erläutern, wie statische Dateien unter dem Klassenpfad zum Web veröffentlicht werden. Geben Sie das Verzeichnis an, das mit der Methode staticFiles.location veröffentlicht werden soll.

In den Beispieleinstellungen können Sie die Datei / spark-demo / src / main / resources / public / css / styles.css abrufen, indem Sie mit einem Webbrowser auf http: // localhost: 8090 / css / styles.css zugreifen. ..

Legen Sie den Verbindungspool mit der Methode "threadPool" fest. Die Argumente sind die maximale Anzahl von Threads, die minimale Anzahl von Threads und das Zeitlimit (Millisekunden) in der angegebenen Reihenfolge.

** ★ Punkt 3 ** Wir haben beschlossen, die Web-API unter Berücksichtigung der Wartbarkeit bei Ergänzungen oder Änderungen als separate Klasse zu definieren.

3.2. Web-API-Klassen

TodoApi.java


package com.example.spark.demo;

import static spark.Spark.*;

import java.util.HashMap;
import java.util.Map;

/**
 *★ Punkt 4
 * Web API for TODO
 */
public class TodoApi {
    //★ Punkt 4
    public static void api() {
        //★ Punkt 5
        TodoService todoService = new TodoService();
        JsonTransformer jsonTransformer = new JsonTransformer();

        //★ Punkt 6
        path("/api", () -> {
            path("/todo", () -> {
                post("", (request, response) -> {
                    String json = request.body();
                    Todo todo = jsonTransformer.fromJson(json, Todo.class);
                    return todoService.create(todo);
                }, jsonTransformer);
                get("/:todoId", (request, response) -> {
                    return todoService.find(request.params(":todoId"));
                }, jsonTransformer);
                put("/:todoId", (request, response) -> {
                    String json = request.body();
                    Todo todo = jsonTransformer.fromJson(json, Todo.class);
                    todo.setTodoId(request.params(":todoId"));
                    return todoService.update(todo);
                }, jsonTransformer);
                delete("/:todoId", (request, response) -> {
                    todoService.delete(request.params(":todoId"));
                    return success();
                }, jsonTransformer);
            });
            //★ Punkt 7
            // set response-type to all request of under '/api'
            after("/*", (request, response) -> {
                response.type("application/json;charset=UTF-8");
            });
        });
    }

    private static Map<String, String> success() {
        Map<String, String> map = new HashMap<String, String>();
        map.put("result", "success!");
        return map;
    }
}

** ★ Punkt 4 ** Definieren Sie die Verarbeitung der Web-API als reguläre Klasse. Da die Spark Framework-API viele statische Methoden enthält, habe ich beschlossen, sie diesmal als statische API-Methode zu definieren.

** ★ Punkt 5 ** Erstellen Sie eine Instanz der Klassen Business Logic (TodoService) und Format Transform (JsonTransformer). Wir werden später über die beiden Klassen sprechen.

** ★ Punkt 6 ** Dies ist der Punkt dieses Artikels.

Weitere Informationen finden Sie unter Offizielle Dokumentationsrouten und Anfrage.

** ★ Punkt 7 ** Sie können die Verarbeitung vor und nach der Web-API mit der Funktion Filter von Spark Framework hinzufügen. Das Beispiel definiert einen "Nach" -Filter, der "application / json; charset = UTF-8" im Antwortheader für alle Anforderungen, deren Pfad unter "/ api" liegt, auf "Inhaltstyp" setzt.

Neben dem Nachfilter gibt es auch Vorher- und Nachher-Filter. Weitere Informationen zu Filtern finden Sie in der offiziellen Dokumentation (http://sparkjava.com/documentation#filters).

3.3. Formatkonvertierungsklasse

JsonTransformer.java


package com.example.spark.demo;

import com.google.gson.Gson;
import spark.ResponseTransformer;

//★ Punkt 8
public class JsonTransformer implements ResponseTransformer {

    private Gson gson = new Gson();

    //★ Punkt 8
    @Override
    public String render(Object model) throws Exception {
        return gson.toJson(model);
    }

    //★ Punkt 9
    public <T> T fromJson(String json, Class<T> classOfT) {
        return gson.fromJson(json, classOfT);
    }
}

** ★ Punkt 8 ** Definiert eine Klasse, die die Schnittstelle "spark.ResponseTransformer" implementiert. Der Zweck dieser Schnittstelle besteht darin, das Verarbeitungsergebnis der API-Methode (das Ergebnis des Lambda-Ausdrucks an Punkt 6) in einen String zu konvertieren, der in die HTTP-Antwort geschrieben werden soll. Implementieren Sie diesen Prozess in render, da @ Override angegeben ist. Dieses Mal wird der im offiziellen Dokument beschriebene Prozess unverändert verwendet und mit GSON in das JSON-Format konvertiert.

** ★ Punkt 9 ** Wie der Name "ResponseTransformer" andeutet, handelt es sich ursprünglich um eine Klasse für die Datenkonvertierung von Antworten. Ich habe mich jedoch entschlossen, die Objektkonvertierung von JSON zum Zeitpunkt der Anforderung auch hier zu konvertieren. (Ich wollte nur GSON-Objekte wiederverwenden)

Übrigens gibt es keinen "RequestTransformer", der Anforderungsdaten in Spark Framework transformiert.

3.4. Geschäftslogikklasse

TodoService.java


package com.example.spark.demo;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

//★ Punkt 10
public class TodoService {

    private Map<String, Todo> store = new HashMap<String, Todo>();

    public Todo find(String todoId) {
        return store.get(todoId);
    }

    public void delete(String todoId) {
        store.remove(todoId);
        System.out.println("delete todoId : " + todoId);
    }
    
    public Todo update(Todo todo) {
        Todo updatedTodo = store.get(todo.getTodoId());
        if (updatedTodo != null) {
            updatedTodo.setTodoTitle(todo.getTodoTitle());
            updatedTodo.setFinished(todo.isFinished());
        }
        return updatedTodo;
    }

    public Todo create(Todo todo) {
        String todoId = UUID.randomUUID().toString();
        Todo registeredTodo = new Todo(todoId, todo.getTodoTitle(), new Date(),
                false);
        store.put(todoId, registeredTodo);
        System.out.println("registeredTodo : " + registeredTodo);
        return registeredTodo;
    }
}

** ★ Punkt 10 ** Implementieren Sie die Geschäftslogik der TODO-App. Es ist jedoch ein geeigneter Dummy-Prozess, da die Funktionen von Spark Framework nicht verwendet werden. Dieses Mal haben wir nicht auf die Datenbank zugegriffen und Map für die In-Memory-CRUD-Verarbeitung verwendet.

4. Erstellen einer ausführbaren JAR

Da es sich um einen Mikrodienst handelt, möchte ich die Ausführung vereinfachen. Ich möchte es als eine ausführbare JAR-Datei wie "uber.jar" erstellen.

pom.xml


<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">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example.spark.demo</groupId>
  <artifactId>spark-demo</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>spark-demo</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <!-- add spark framework -->
    <dependency>
      <groupId>com.sparkjava</groupId>
      <artifactId>spark-core</artifactId>
      <version>2.7.1</version>
    </dependency>
    <!-- add gson -->
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.8.2</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <!-- java8 -->
  <properties>
    <java.version>1.8</java.version>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <maven.compiler.source>${java.version}</maven.compiler.source>
  </properties>
  <!-- add for executable jar -->
  <build>
    <plugins>
      <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <executions>
            <execution>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
            </execution>
          </executions>
          <configuration>
            <archive>
              <manifest>
                <addClasspath>true</addClasspath>
                <mainClass>com.example.spark.demo.App</mainClass>
              </manifest>
            </archive>
            <descriptorRefs>
              <descriptorRef>jar-with-dependencies</descriptorRef>
            </descriptorRefs>
          </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Sobald Sie eine ausführbare JAR-Datei haben, führen Sie sie mit "java -jar" aus.

C:\tmp\spark\spark-demo>java -jar target/spark-demo-1.0-SNAPSHOT-jar-with-dependencies.jar
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

5. Schließlich

Dieses Mal erklärte ich die Implementierung von Mikrodiensten mit Spark Framework. Es ist sehr einfach und leicht zu implementieren und kann als einzelne ausführbare JAR-Datei erstellt werden. Ich denke, es ist einfach zu veröffentlichen. In dem Beispiel wird die Eingabeprüfung weggelassen, aber es ist tatsächlich ein notwendiger Prozess. Java-json-tools / json-schema-validator beim Überprüfen der Eingabe als JSON, beim Überprüfen der Eingabe als Java Bean Validation wird empfohlen.

Recommended Posts

Einfacher Mikroservice mit Spark Framework!
SaveAsBinaryFile mit Spark (Teil 2)
(Java) Einfache BDD mit Spektrum?
Microservices mit DevOps nehmen Änderungen vor
Einfaches Web-Scraping mit Jsoup
Einfache Bibliothekseinführung mit Maven!
Erstellen Sie mit Spring Boot einen Mikrodienst
Hallo Welt, mit Asakusa Framework!
Mit Commons DbUtils können Sie ganz einfach JDBC-Anrufe tätigen
Doppelte Übermittlung von Maßnahmen mit Play Framework
Einfache Eingabeprüfung mit Bean Validation!
Datenverknüpfung mit Spark und Cassandra
Einfacher Datenbankzugriff mit Java Sql2o
Testen Sie den Spring Framework Controller mit Junit
Microservices mit Docker- und Cloud-Leistung