[JAVA] Essayez les services Web RESTful avec l'archétype de conteneur de Nablarch

What's?

Je voulais faire semblant d'être Naplarque pendant un moment.

Je voudrais définir un petit thème et l'essayer depuis le début.

Essayez-le

Référence) Nablarch 5u18 est sorti!

environnement

Cet environnement est ici.

$ java --version
openjdk 11.0.9 2020-10-20
OpenJDK Runtime Environment (build 11.0.9+11-Ubuntu-0ubuntu1.20.04)
OpenJDK 64-Bit Server VM (build 11.0.9+11-Ubuntu-0ubuntu1.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.9, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-52-generic", arch: "amd64", family: "unix"


$ docker version
Client: Docker Engine - Community
 Version:           19.03.13
 API version:       1.40
 Go version:        go1.13.15
 Git commit:        4484c46d9d
 Built:             Wed Sep 16 17:02:52 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.13
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       4484c46d9d
  Built:            Wed Sep 16 17:01:20 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.3.7
  GitCommit:        8fba4e9a7d01810a393d5d25a3621dc101981175
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

Créer un projet

Jetez un œil à la mise en route.

Getting Started

Si vous souhaitez créer une application à part entière, créez-la à partir d'un projet vierge.

Il semble préférable de commencer avec un projet vierge, alors faisons-en un projet vierge.

Projet vierge

Depuis Nablarch 5u18, la prise en charge des conteneurs est incluse, alors utilisez ceci. Vous pouvez créer une image Docker avec Jib.

Conteneurisation Docker

Procédure de configuration.

Configuration initiale du projet de service Web RESTful pour le conteneur

J'ai un fichier batch pour Windows, mais comme cet environnement est Linux, je lance directement maven-archetype-plugin: 2.4: generate.

$ mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate \
  -DinteractiveMode=false \
  -DarchetypeGroupId=com.nablarch.archetype \
  -DarchetypeArtifactId=nablarch-container-jaxrs-archetype \
  -DarchetypeVersion=5u18 \
  -DgroupId=com.example \
  -DartifactId=hello-nablarch-restful \
  -Dversion=0.0.1 \
  -Dpackage=com.example

C'est fait.

[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: nablarch-container-jaxrs-archetype:5u18
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.example
[INFO] Parameter: artifactId, Value: hello-nablarch-restful
[INFO] Parameter: version, Value: 0.0.1
[INFO] Parameter: package, Value: com.example
[INFO] Parameter: packageInPathFormat, Value: com/example
[INFO] Parameter: package, Value: com.example
[INFO] Parameter: groupId, Value: com.example
[INFO] Parameter: artifactId, Value: hello-nablarch-restful
[INFO] Parameter: version, Value: 0.0.1
[INFO] project created from Archetype in dir: /path/to/hello-nablarch-restful
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.583 s
[INFO] Finished at: 2020-11-11T11:10:34+09:00
[INFO] ------------------------------------------------------------------------

Déplacé dans le projet.

$ cd hello-nablarch-restful

Jetons un coup d'œil rapide au fichier.

$ find -type f
./README.md
./pom.xml
./.gitignore
./h2/bin/h2-1.3.176.jar
./h2/bin/h2w.bat
./h2/bin/h2.sh
./h2/bin/h2.bat
./h2/db/SAMPLE.h2.db
./h2/db/SAMPLE.h2.db.org
./db/ddl/db2/create.sql
./db/ddl/db2/drop.sql
./db/ddl/sqlserver/create.sql
./db/ddl/sqlserver/drop.sql
./db/ddl/oracle/create.sql
./db/ddl/oracle/drop.sql
./db/ddl/postgresql/create.sql
./db/ddl/postgresql/drop.sql
./db/ddl/h2/create.sql
./db/ddl/h2/drop.sql
./db/data/db2/data.sql
./db/data/sqlserver/data.sql
./db/data/oracle/data.sql
./db/data/postgresql/data.sql
./db/data/h2/data.sql
./src/main/webapp/WEB-INF/web.xml
./src/main/resources/entity/data-model_sqlserver.edm
./src/main/resources/entity/data-model.edm
./src/main/resources/entity/data-model_postgresql.edm
./src/main/resources/entity/data-model_db2.edm
./src/main/resources/entity/data-model_oracle.edm
./src/main/resources/rest-boot.xml
./src/main/resources/env.config
./src/main/resources/META-INF/services/nablarch.core.repository.di.config.externalize.ExternalizedComponentDefinitionLoader
./src/main/resources/rest-component-configuration.xml
./src/main/resources/messages.properties
./src/main/resources/data-source.xml
./src/main/resources/log.properties
./src/main/resources/app-log.properties
./src/main/resources/common.config
./src/main/jib/usr/local/tomcat/conf/server.xml
./src/main/jib/usr/local/tomcat/conf/logging.properties
./src/main/java/com/example/entity/package-info.java
./src/main/java/com/example/entity/SampleUser.java
./src/main/java/com/example/package-info.java
./src/main/java/com/example/domain/package-info.java
./src/main/java/com/example/domain/SampleDomainBean.java
./src/main/java/com/example/domain/SampleDomainManager.java
./src/main/java/com/example/SampleAction.java
./src/main/java/com/example/dto/SampleUserListDto.java
./src/test/resources/log.properties
./src/test/resources/unit-test.xml
./src/test/resources/data/SAMPLE_USER.csv
./src/test/java/com/example/SampleApiTest.java
./src/test/java/com/example/SampleActionTest.java

La configuration est expliquée ici.

Configuration de l'archétype Maven (https://nablarch.github.io/docs/5u18/doc/application_framework/application_framework/blank_project/MavenModuleStructures/index.html)

Jetons un œil au profil.

$ mvn help:all-profiles
[INFO] Scanning for projects...
[WARNING] The POM for org.eclipse.m2e:lifecycle-mapping:jar:1.0.0 is missing, no dependency information available
[WARNING] Failed to retrieve plugin descriptor for org.eclipse.m2e:lifecycle-mapping:1.0.0: Plugin org.eclipse.m2e:lifecycle-mapping:1.0.0 or one of its dependencies could not be resolved: Failure to find org.eclipse.m2e:lifecycle-mapping:jar:1.0.0 in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced
[INFO] 
[INFO] -----------------< com.example:hello-nablarch-restful >-----------------
[INFO] Building hello-nablarch-restful 0.0.1
[INFO] --------------------------------[ war ]---------------------------------
[WARNING] The POM for org.eclipse.m2e:lifecycle-mapping:jar:1.0.0 is missing, no dependency information available
[WARNING] Failed to retrieve plugin descriptor for org.eclipse.m2e:lifecycle-mapping:1.0.0: Plugin org.eclipse.m2e:lifecycle-mapping:1.0.0 or one of its dependencies could not be resolved: Failure to find org.eclipse.m2e:lifecycle-mapping:jar:1.0.0 in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced
[INFO] 
[INFO] --- maven-help-plugin:3.2.0:all-profiles (default-cli) @ hello-nablarch-restful ---
[INFO] Listing Profiles for Project: com.example:hello-nablarch-restful:war:0.0.1
  Profile Id: BACKUP (Active: false , Source: pom)
  Profile Id: gsp (Active: false , Source: pom)
  Profile Id: ossrh (Active: false , Source: pom)

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.106 s
[INFO] Finished at: 2020-11-11T11:06:10+09:00
[INFO] ------------------------------------------------------------------------

Les archétypes pour conteneurs ne semblent pas avoir le concept de profils pour l'environnement.

Paramètres d'environnement de production de conteneurs

Il semble que la valeur écrite dans env.config soit remplacée par la variable d'environnement.

Lors de la création d'un projet, cela ressemble à ceci.

$ grep -vE '^$|^#' src/main/resources/env.config 
nablarch.db.jdbcDriver=org.h2.Driver
nablarch.db.url=jdbc:h2:./h2/db/SAMPLE
nablarch.db.user=SAMPLE
nablarch.db.password=SAMPLE
nablarch.db.schema=PUBLIC
nablarch.db.maxPoolSize=5
nablarch.db.minimumIdle=5
nablarch.db.connectionTimeout=30000
nablarch.db.idleTimeout=600000
nablarch.db.maxLifetime=1800000
nablarch.db.validationTimeout=5000
nablarch.codeCache.loadOnStartUp=false

Il semble également y avoir un exemple de classe Action

src/main/java/com/example/SampleAction.java

package com.example;

import com.example.dto.SampleUserListDto;
import com.example.entity.SampleUser;
import nablarch.common.dao.EntityList;
import nablarch.common.dao.UniversalDao;
import nablarch.fw.web.HttpRequest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 *Classe d'action pour la confirmation de la communication.
 *
 * @obsolète TODO C'est une classe pour vérifier la communication. Veuillez le supprimer une fois la confirmation terminée.
 */
@Path("/find")
public class SampleAction {

    /**
     *Processus de recherche.
     * <p>
     *Utilisez JSON pour la réponse.
     * </p>
     *
     * @param req requête HTTP
     * @retourner les informations utilisateur(JSON)
     */
    @GET
    @Path("/json")
    @Produces(MediaType.APPLICATION_JSON)
    public EntityList<SampleUser> findProducesJson(HttpRequest req) {
        return UniversalDao.findAll(SampleUser.class);
    }

    /**
     *Processus de recherche.
     * <p>
     *Utilisez XML pour la réponse.
     * </p>
     *
     * @param req requête HTTP
     * @retourner les informations utilisateur(XML)
     */
    @GET
    @Path("/xml")
    @Produces(MediaType.APPLICATION_XML)
    public SampleUserListDto findProducesXml(HttpRequest req) {
        EntityList<SampleUser> sampleUserList = UniversalDao.findAll(SampleUser.class);
        return new SampleUserListDto(sampleUserList);
    }

}

Pour le moment, suivons la méthode de confirmation de communication.

Confirmation de la communication

Tout d'abord, créez une image Docker.

$ mvn package jib:dockerBuild -DskipTests=true

J'ai pu le faire.

$ docker image ls | grep hello
hello-nablarch-restful             0.0.1               a4b772a979de        50 years ago        448MB
hello-nablarch-restful             latest              a4b772a979de        50 years ago        448MB

L'image de base par défaut provient de Tomcat.

Créer une image de conteneur

Je vais le démarrer.

$ docker container run -it --rm -p 8080:8080 -v `pwd`/h2:/usr/local/tomcat/h2 hello-nablarch-restful:0.0.1

Confirmation. Cela semble correct pour le moment.

$ curl localhost:8080/find/json
[{"userId":1,"kanjiName":"Rakutaro Nabe","kanaName":"Naburakutaro"},{"userId":2,"kanjiName":"Rakujiro Nabe","kanaName":"Naburakujiro"}]

Au fait, si vous oubliez de spécifier Volume dans cette procédure, la base de données disparaîtra et vous échouerez (j'étais accro à l'ignorer).

-v `pwd`/h2:/usr/local/tomcat/h2

Exécuter l'image du conteneur

XML-Less DI Configuration

Ensuite, utilisons DI légèrement. Il semble que DI utilisant des annotations puisse être fait, je vais donc l'utiliser.

Créer un objet d'une classe annotée

Il semble créer une sous-classe de la classe AnnotationComponentDefinitionLoader.

Quel est l'endroit pour le mettre? J'ai pensé, alors référez-vous à ce qui suit.

Référence de développement de services pour la configuration de l'API SPA + REST

https://github.com/Fintan-contents/example-chat/blob/master/backend/src/main/java/com/example/system/nablarch/di/ExampleChatComponentDefinitionLoader.java

Eh bien, en conséquence, je suis resté simple.

src/main/java/com/example/system/HelloRestComponentDefinitionLoader.java

package com.example.system;

import nablarch.core.repository.di.config.externalize.AnnotationComponentDefinitionLoader;

public class HelloRestComponentDefinitionLoader extends AnnotationComponentDefinitionLoader {
    @Override
    protected String getBasePackage() {
        return "com.example";
    }
}

La méthode getBasePackage retourne le package à analyser.

J'incorpore cela dans le gimmick ServiceLoader, mais il semble que le fichier cible existe déjà.

src/main/resources/META-INF/services/nablarch.core.repository.di.config.externalize.ExternalizedComponentDefinitionLoader

nablarch.core.repository.di.config.externalize.OsEnvironmentVariableExternalizedLoader
nablarch.core.repository.di.config.externalize.SystemPropertyExternalizedLoader

Ajouté ici.

nablarch.core.repository.di.config.externalize.OsEnvironmentVariableExternalizedLoader
nablarch.core.repository.di.config.externalize.SystemPropertyExternalizedLoader
com.example.system.HelloRestComponentDefinitionLoader

Créez une classe qui faisait partie de l'échantillon et transférez le processus d'acquisition de données. Ajoutez l'annotation @ SystemRepositoryComponent.

src/main/java/com/example/service/UserService.java

package com.example.service;

import com.example.entity.SampleUser;
import nablarch.common.dao.EntityList;
import nablarch.common.dao.UniversalDao;
import nablarch.core.repository.di.config.externalize.annotation.SystemRepositoryComponent;

@SystemRepositoryComponent
public class UserService {
    public EntityList<SampleUser> findUsers() {
        return UniversalDao.findAll(SampleUser.class);
    }
}

Alors, créez une classe Action qui l'utilise.

src/main/java/com/example/HelloAction.java

package com.example;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.example.entity.SampleUser;
import com.example.service.UserService;
import nablarch.common.dao.EntityList;
import nablarch.core.repository.di.config.externalize.annotation.SystemRepositoryComponent;

@SystemRepositoryComponent
@Path("/hello")
public class HelloAction {
    UserService userService;

    public HelloAction(UserService userService) {
        this.userService = userService;
    }

    @GET
    @Path("/json")
    @Produces(MediaType.APPLICATION_JSON)
    public EntityList<SampleUser> users() {
        return userService.findUsers();
    }
}

Dans le constructeur, recevons le composant.

    public HelloAction(UserService userService) {
        this.userService = userService;
    }

Il semble que des paramètres supplémentaires soient nécessaires pour gérer la classe Action dans un conteneur DI.

Gérer la classe Action avec le conteneur DI

Ceci est un extrait.

src/main/resources/rest-component-configuration.xml

  <!--Paramètres de mappage de package-->
  <component name="packageMapping" class="nablarch.integration.router.PathOptionsProviderRoutesMapping">
    <property name="pathOptionsProvider">
      <component class="nablarch.integration.router.jaxrs.JaxRsPathOptionsProvider">
        <property name="applicationPath" value="${nablarch.webApi.applicationPath}"/>
        <property name="basePackage" value="${nablarch.commonProperty.basePackage}"/>
      </component>
    </property>
    <property name="methodBinderFactory">
      <component class="nablarch.fw.jaxrs.JaxRsMethodBinderFactory">
        <property name="handlerList">
          <component class="nablarch.integration.jaxrs.jersey.JerseyJaxRsHandlerListFactory"/>
        </property>
      </component>
    </property>
  </component>

Ajoutez SystemRepositoryDelegateFactory en tant que delegateFactory.

  <!--Paramètres de mappage de package-->
  <component name="packageMapping" class="nablarch.integration.router.PathOptionsProviderRoutesMapping">
    <property name="pathOptionsProvider">
      <component class="nablarch.integration.router.jaxrs.JaxRsPathOptionsProvider">
        <property name="applicationPath" value="${nablarch.webApi.applicationPath}"/>
        <property name="basePackage" value="${nablarch.commonProperty.basePackage}"/>
      </component>
    </property>
    <property name="methodBinderFactory">
      <component class="nablarch.fw.jaxrs.JaxRsMethodBinderFactory">
        <property name="handlerList">
          <component class="nablarch.integration.jaxrs.jersey.JerseyJaxRsHandlerListFactory"/>
        </property>
      </component>
    </property>
    <property name="delegateFactory">
        <component class="nablarch.fw.handler.SystemRepositoryDelegateFactory"/>
    </property>
  </component>

Après cela, créez à nouveau l'image Docker et démarrez-la.

$ mvn package jib:dockerBuild -DskipTests=true
$ docker container run -it --rm -p 8080:8080 -v `pwd`/h2:/usr/local/tomcat/h2 hello-nablarch-restful:0.0.1 

Confirmation.

$ curl localhost:8080/hello/json
[{"userId":1,"kanjiName":"Rakutaro Nabe","kanaName":"Naburakutaro"},{"userId":2,"kanjiName":"Rakujiro Nabe","kanaName":"Naburakujiro"}]

C'est bon.

Changer la base de données en PostgreSQL

Enfin, changeons la base de données utilisée de H2 en PostgreSQL.

Procédure de modification du SGBDR à utiliser

Dans le SGBDR, l'utilisateur à utiliser pour la connexion et le schéma ont déjà été créés.

Parce que ça veut dire ça.

PostgreSQL décide d'utiliser l'image Docker.

postgres

Même si c'est 12.2 ou plus, ça ira ...

Environnement d'exploitation

En regardant la structure du projet, il semble que le fichier SQL soit inclus

Configuration de l'archétype Maven (https://nablarch.github.io/docs/5u18/doc/application_framework/application_framework/blank_project/MavenModuleStructures/index.html)

Convertir en UTF-8 (écrit en Shift_JIS ...).

$ iconv -f sjis -t utf-8 db/ddl/postgresql/create.sql -o db/ddl/postgresql/create.sql.utf8
$ iconv -f sjis -t utf-8 db/data/postgresql/data.sql -o db/data/postgresql/data.sql.utf8

Démarrez PostgreSQL.

$ docker container run -it --rm --name postgres \
  -v `pwd`/db:/data/db \
  -e POSTGRES_USER=postgres_user \
  -e POSTGRES_PASSWORD=postgres_password \
  -e POSTGRES_DB=mydatabase \
  postgres:13.0

Entrez dans le conteneur, exécutez DDL et enregistrez les données.

$ docker container exec -it postgres bash
$ psql -U postgres_user -f /data/db/ddl/postgresql/create.sql.utf8 mydatabase
$ psql -U postgres_user -f /data/db/data/postgresql/data.sql.utf8 mydatabase

Cette fois, traitons-le comme un autre hôte sans le lier au port côté hôte. Vérifiez l'adresse IP du conteneur.

$ docker container inspect postgres | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",

Remplacement du pilote JDBC de H2 vers PostgreSQL

    <!-- TODO:Modifiez le pilote JDBC pour qu'il corresponde au produit DB utilisé dans le projet.-->
    <!--
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>1.3.176</version>
      <scope>runtime</scope>
    </dependency>
    -->
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.18</version>
      <scope>runtime</scope>
    </dependency>

Paramètres de connexion fixes. Vous pouvez l'écraser avec une variable d'environnement, mais cette fois c'est le cas.

src/main/resources/env.config

$ grep nablarch.db src/main/resources/env.config 
#nablarch.db.jdbcDriver=org.h2.Driver
nablarch.db.jdbcDriver=org.postgresql.Driver

#nablarch.db.url=jdbc:h2:./h2/db/SAMPLE
nablarch.db.url=jdbc:postgresql://172.17.0.2:5432/mydatabase

#nablarch.db.user=SAMPLE
nablarch.db.user=postgres_user

#nablarch.db.password=SAMPLE
nablarch.db.password=postgres_password

#nablarch.db.schema=PUBLIC
nablarch.db.schema=public

Créer une image de conteneur.

$ mvn clean
$ mvn package jib:dockerBuild -DskipTests=true

Commencez.

$ docker container run -it --rm -p 8080:8080 hello-nablarch-restful:0.0.1

Confirmation.

$ curl localhost:8080/hello/json
][{"userId":1,"kanjiName":"Rakutaro Nabe","kanaName":"Naburakutaro"},{"userId":2,"kanjiName":"Rakujiro Nabe","kanaName":"Naburakujiro"}]

J'ai pu le faire.

Recommended Posts

Essayez les services Web RESTful avec l'archétype de conteneur de Nablarch
Essayer avec la déclaration de ressources dans l'application Web
Essayez d'utiliser un autre conteneur de servlet Jetty avec Docker
Essayez d'utiliser un conteneur DI avec Laravel et Spring Boot