JavaLiteガイド - RESTful CRUDアプリケーションの構築

1前書き

  • JavaLite は、すべての開発者がアプリケーションを構築するときに対処しなければならない一般的な作業を簡素化するためのフレームワークの集まりです。

このチュートリアルでは、単純なAPIの構築に重点を置いたJavaLiteの機能を見ていきます。

2セットアップ

このチュートリアルを通して、簡単なRESTful CRUDアプリケーションを作成します。そのために、 ActiveWebとActiveJDBC を使用します。JavaLiteが統合する2つのフレームワークです。

それでは始めましょう、私たちが必要とする最初の依存関係を追加しましょう:

<dependency>
    <groupId>org.javalite</groupId>
    <artifactId>activeweb</artifactId>
    <version>1.15</version>
</dependency>

ActiveWebアーティファクトにはActiveJDBCが含まれているため、別に追加する必要はありません。最新のhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.javalite%22%20AND%20a%3A%22activeweb%22[activeweb]バージョンが見つかることに注意してください。 Maven Centralで。

2番目に必要な依存関係は データベースコネクタ です。この例では、MySQLを使用するので、追加する必要があります。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.45</version>
</dependency>

繰り返しますが、最新のhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22mysql%22%20AND%20a%3A%22mysql-connector-java%22[mysql-connector-java]依存関係はMaven Centralにあります。

追加しなければならない最後の依存関係は、JavaLite特有のものです。

<plugin>
    <groupId>org.javalite</groupId>
    <artifactId>activejdbc-instrumentation</artifactId>
    <version>1.4.13</version>
    <executions>
        <execution>
            <phase>process-classes</phase>
            <goals>
                <goal>instrument</goal>
            </goals>
        </execution>
    </executions>
</plugin>

最新のhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.javalite%22%20AND%20a%3A%22activejdbc-instrumentation%22[activejdbc-instrumentation]プラグインも可能Maven Centralで見つけることができます。

これらすべてを整えて、エンティティ、テーブル、マッピングから始める前に、私たちはhttp://javalite.io/activejdbc#supported-databases[supported databases]の1つが稼働していることを確認します。前に述べたように、私たちはMySQLを使います。

これで、オブジェクトリレーショナルマッピングから始める準備が整いました。

3オブジェクトリレーショナルマッピング

3.1. マッピングとインスツルメンテーション

私たちの主要なエンティティとなる Product クラスを作成することから始めましょう。

public class Product {}

そして、それに対応するテーブルも作成しましょう。

CREATE TABLE PRODUCTS (
    id int(11) DEFAULT NULL auto__increment PRIMARY KEY,
    name VARCHAR(128)
);

最後に、マッピングを行うために Product クラスを変更することができます。

public class Product extends Model {}

org.javalite.activejdbc.Model クラスを拡張するだけです。

  • ActiveJDBCはデータベース からDBスキーマパラメータを推測します。この機能のおかげで、 ゲッターやセッターや注釈を追加する必要はありません**

さらに、ActiveJDBCは Product クラスを PRODUCTS テーブルにマップする必要があることを自動的に認識します。これは英語の活用を利用して、単数形のモデルを複数形の表に変換します。そして、はい、それは同様に例外で動作します。

マッピングを機能させるために必要なことがもう1つあります。

計装** インストルメンテーションはActiveJDBCに必要な追加のステップであり、ゲッター、セッター、およびDAOのようなメソッドを持っているかのように Product クラスを操作できます。

インストルメンテーションを実行した後は、次のようなことができるようになります。

Product p = new Product();
p.set("name","Bread");
p.saveIt();

または

List<Product> products = Product.findAll();

これが activejdbc-instrumentation プラグインが登場するところです。pomには既に依存関係があるので、ビルド中にクラスがインスツルメントされているのがわかります。

...[INFO]--- activejdbc-instrumentation:1.4.11:instrument (default) @ javalite ---
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **  START INSTRUMENTATION ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
Directory: ...\tutorials\java-lite\target\classes
Instrumented class: .../tutorials/java-lite/target/classes/app/models/Product.class
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **  END INSTRUMENTATION ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
...

次に、これが機能していることを確認するための簡単なテストを作成します。

3.2. テスト中

最後に、マッピングをテストするために、データベースへの接続を開き、新しい商品を保存してそれを取得するという3つの簡単な手順に従います。

@Test
public void givenSavedProduct__WhenFindFirst__ThenSavedProductIsReturned() {

    Base.open(
      "com.mysql.jdbc.Driver",
      "jdbc:mysql://localhost/dbname",
      "user",
      "password");

    Product toSaveProduct = new Product();
    toSaveProduct.set("name", "Bread");
    toSaveProduct.saveIt();

    Product savedProduct = Product.findFirst("name = ?", "Bread");

    assertEquals(
      toSaveProduct.get("name"),
      savedProduct.get("name"));
}

これらすべて(およびそれ以上)は、空のモデルと計装を使用するだけで可能です。

4コントローラー

マッピングの準備ができたので、アプリケーションとそのCRUDメソッドについて考え始めます。

そのために、HTTPリクエストを処理するコントローラを利用します。

ProductsController を作成しましょう。

@RESTful
public class ProductsController extends AppController {

    public void index() {
       //...
    }

}

この実装では、ActiveWebは自動的に index() メソッドを次のURIにマッピングします。

http://<host>:<port>/products

@ RESTful 、** というアノテーションが付けられたコントローラは、異なるURIに自動的にマッピングされた固定されたメソッドのセットを提供します。

| =================================================== ============ | コントローラメソッド | HTTPメソッド | URI | | CREATE | create() | POST | http://ホスト:ポート/製品 | READ ONE | show() | GET | http://ホスト:ポート/製品/\ {id} |すべて読み取り| インデックス() | GET | http://ホスト:ポート/製品 | UPDATE | update() | PUT | http://ホスト:ポート/製品/\ {id} | DELETE | destroy() | DELETE | http://ホスト:port/products/\ {id} | ==================================== ===========================

そして、この一連のメソッドを ProductsController に追加すると、

@RESTful
public class ProductsController extends AppController {

    public void index() {
       //code to get all products
    }

    public void create() {
       //code to create a new product
    }

    public void update() {
       //code to update an existing product
    }

    public void show() {
       //code to find one product
    }

    public void destroy() {
       //code to remove an existing product
    }
}

ロジックの実装に移る前に、構成する必要があるいくつかの点について簡単に説明します。

5構成

ActiveWebは主に規約に基づいており、プロジェクト構造はその一例です。 ActiveWebプロジェクトは定義済みのパッケージレイアウトに従う必要があります :

src
 |----main
       |----java.app
       |     |----config
       |     |----controllers
       |     |----models
       |----resources
       |----webapp
             |----WEB-INF
             |----views

見ておく必要がある特定のパッケージが1つあります - a _pp.config _

そのパッケージの中に、3つのクラスを作成します。

public class DbConfig extends AbstractDBConfig {
    @Override
    public void init(AppContext appContext) {
        this.configFile("/database.properties");
    }
}
  • このクラスは、必要なパラメータを含むプロジェクトのルートディレクトリにあるプロパティファイルを使用して** データベース接続を設定します。

development.driver=com.mysql.jdbc.Driver
development.username=user
development.password=password
development.url=jdbc:mysql://localhost/dbname

これにより、マッピングテストの最初の行で行ったことを自動的に置き換える接続が作成されます。

app.config パッケージ内に含める必要がある2番目のクラスは次のとおりです。

public class AppControllerConfig extends AbstractControllerConfig {

    @Override
    public void init(AppContext appContext) {
        add(new DBConnectionFilter()).to(ProductsController.class);
    }
}

このコードは、設定したばかりの接続をコントローラにバインドします。

3番目のクラスは、アプリケーションのコンテキストを設定します。

public class AppBootstrap extends Bootstrap {
    public void init(AppContext context) {}
}

3つのクラスを作成した後、設定に関する最後のことは、 webapp/WEB-INF ディレクトリの下に web.xml ファイルを作成することです。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns=...>

    <filter>
        <filter-name>dispatcher</filter-name>
        <filter-class>org.javalite.activeweb.RequestDispatcher</filter-class>
        <init-param>
            <param-name>exclusions</param-name>
            <param-value>css,images,js,ico</param-value>
        </init-param>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>dispatcher</filter-name>
        <url-pattern>/** </url-pattern>
    </filter-mapping>

</web-app>

構成が完了したので、先に進んでロジックを追加します。

6. CRUDロジックの実装

Product クラスが提供するDAOのような機能を使えば、基本的なCRUD機能を追加するのはとても簡単です。

@RESTful
public class ProductsController extends AppController {

    private ObjectMapper mapper = new ObjectMapper();

    public void index() {
        List<Product> products = Product.findAll();
       //...
    }

    public void create() {
        Map payload = mapper.readValue(getRequestString(), Map.class);
        Product p = new Product();
        p.fromMap(payload);
        p.saveIt();
       //...
    }

    public void update() {
        Map payload = mapper.readValue(getRequestString(), Map.class);
        String id = getId();
        Product p = Product.findById(id);
        p.fromMap(payload);
        p.saveIt();
       //...
    }

    public void show() {
        String id = getId();
        Product p = Product.findById(id);
       //...
    }

    public void destroy() {
        String id = getId();
        Product p = Product.findById(id);
        p.delete();
       //...
    }
}

簡単でしょ?しかし、これはまだ何も返していません。そのためには、ビューをいくつか作成する必要があります。

7. 閲覧数

  • ActiveWebはテンプレートエンジンとして使用し、そのテンプレートはすべて src/main/webapp/WEB-INF/views 。の下に配置する必要があります。

そのディレクトリ内で、ビューを products というフォルダに配置します(コントローラと同じ)。 __product.ftl という最初のテンプレートを作成しましょう。

{
    "id" : ${product.id},
    "name" : "${product.name}"
}

現時点で、これがJSONレスポンスであることは明らかです。もちろん、これは1つの製品に対してのみ機能するので、先に進んで index.ftl という別のテンプレートを作成しましょう。

----[<@render partial="product" collection=products/>]----
  • これは基本的に products という名前のコレクションをレンダリングし、それぞれのコレクションは __product.ftl でフォーマットされます。

最後に、コントローラからの結果を対応するビューにバインドする必要があります。

@RESTful
public class ProductsController extends AppController {

    public void index() {
        List<Product> products = Product.findAll();
        view("products", products);
        render();
    }

    public void show() {
        String id = getId();
        Product p = Product.findById(id);
        view("product", p);
        render("__product");
    }
}

最初のケースでは、 products という名前のテンプレートコレクションに products リストを割り当てます。

その後、ビューを指定していないので、 index.ftl が使用されます。

2番目の方法では、ビューの要素 product にproduct p を割り当て、レンダリングするビューを明示的に指定します。

ビュー message.ftl を作成することもできます。

{
    "message" : "${message}",
    "code" : ${code}
}

そして、 ProductsController のメソッドのいずれかから呼び出します。

view("message", "There was an error.", "code", 200);
render("message");

それでは、最後の ProductsController を見てみましょう。

@RESTful
public class ProductsController extends AppController {

    private ObjectMapper mapper = new ObjectMapper();

    public void index() {
        view("products", Product.findAll());
        render().contentType("application/json");
    }

    public void create() {
        Map payload = mapper.readValue(getRequestString(), Map.class);
        Product p = new Product();
        p.fromMap(payload);
        p.saveIt();
        view("message", "Successfully saved product id " + p.get("id"), "code", 200);
        render("message");
    }

    public void update() {
        Map payload = mapper.readValue(getRequestString(), Map.class);
        String id = getId();
        Product p = Product.findById(id);
        if (p == null) {
            view("message", "Product id " + id + " not found.", "code", 200);
            render("message");
            return;
        }
        p.fromMap(payload);
        p.saveIt();
        view("message", "Successfully updated product id " + id, "code", 200);
        render("message");
    }

    public void show() {
        String id = getId();
        Product p = Product.findById(id);
        if (p == null) {
            view("message", "Product id " + id + " not found.", "code", 200);
            render("message");
            return;
        }
        view("product", p);
        render("__product");
    }

    public void destroy() {
        String id = getId();
        Product p = Product.findById(id);
        if (p == null) {
            view("message", "Product id " + id + " not found.", "code", 200);
            render("message");
            return;
        }
        p.delete();
        view("message", "Successfully deleted product id " + id, "code", 200);
        render("message");
    }

    @Override
    protected String getContentType() {
        return "application/json";
    }

    @Override
    protected String getLayout() {
        return null;
    }
}

これでアプリケーションは完成し、実行する準備が整いました。

8アプリケーションの実行

Jettyプラグインを使用します。

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.4.8.v20171121</version>
</plugin>

最新のhttps://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.eclipse.jetty%22%20AND%20a%3A%22jetty-maven-plugin%22[jetty-mavenを検索してください。 -plugin]Maven Centralで。

これで準備が整いました。 アプリケーションを実行できます

mvn jetty:run

いくつかの製品を作りましょう。

$ curl -X POST http://localhost:8080/products
  -H 'content-type: application/json'
  -d '{"name":"Water"}'
{
    "message" : "Successfully saved product id 1",
    "code" : 200
}
$ curl -X POST http://localhost:8080/products
  -H 'content-type: application/json'
  -d '{"name":"Bread"}'
{
    "message" : "Successfully saved product id 2",
    "code" : 200
}
  1. それらを読みます:

$ curl -X GET http://localhost:8080/products[    {
        "id" : 1,
        "name" : "Water"
    },
    {
        "id" : 2,
        "name" : "Bread"
    }]----

それらのうちの1つを更新します。

[source,bash,gutter:,true]

$ curl -X PUT http://localhost:8080/products/1 -H 'content-type: application/json' -d '{"name":"Juice"}' { "message" : "Successfully updated product id 1", "code" : 200 }

...先ほど更新したものを読んでください。

[source,bash,gutter:,true]

$ curl -X GET http://localhost:8080/products/1 { "id" : 1, "name" : "Juice" }

最後に、削除することができます。

[source,bash,gutter:,true]

$ curl -X DELETE http://localhost:8080/products/2 { "message" : "Successfully deleted product id 2", "code" : 200 }

[[conclusions]]

===  **  9結論**

JavaLiteには、開発者がアプリケーションを短時間で起動して実行できるようにするためのツールが多数あります。ただし、規則に基づいてコードを作成するとコードがよりクリーンで単純になりますが、クラス、パッケージ、およびファイルの名前と場所を理解するにはしばらく時間がかかります。

これはActiveWebとActiveJDBCの紹介にすぎません。詳細はhttp://javalite.io[Webサイト]にあり、https://github.com/eugenp/tutorials/tree/master/java-で当社の製品アプリケーションを探してください。 lite[Githubプロジェクト]。