13.1 JavaサーブレットでのJSON返却

これまでの章で、JavaScript で JSON を扱う方法や、Fetch API で外部の Web API からデータを取得する方法を学びました。しかし、実際の業務では、自社のシステムで動いている Java サーブレットと JavaScript が連携して動作することが多くあります。
この節では、Java サーブレット側で JSON データを返却する方法を学びます

13.1.1 サーブレットで JSON を返却する方法

Java サーブレットでは、Java のオブジェクトを JSON 文字列に変換して、レスポンスとして返却します。

基本的な流れ

  1. Java のオブジェクトまたは ArrayList を準備
  2. JSON 変換ライブラリ(Jackson)を使って JSON 文字列に変換
  3. レスポンスの Content-Type を application/json に設定
  4. JSON 文字列をレスポンスに書き出す

13.1.2 Jackson ライブラリの導入

Java でオブジェクトを JSON 形式に変換するには、専用の「ライブラリ」を使うのが一般的です。有名なものに「GSON(ジーソン)」と「Jackson(ジャクソン)」がありますが、現在の現場で最も標準的に使われている Jackson をこの章では採用します。
実務では「Maven」などの管理ツールを使ってライブラリを管理しますが、まずは基本を理解するために、jar ファイルを直接プロジェクトに登録する方法を確認しましょう。

jar ファイルの配置手順

  1. Jackson の公式ページ等から必要な jar ファイル(jackson-databind、jackson-core、jackson-annotations)をダウンロードします。
  2. Eclipse のプロジェクト内の src/main/webapp/WEB-INF/lib フォルダに、これらのファイルをコピーします。
  3. プロジェクトを右クリック >「リフレッシュ」を行い、ライブラリが認識されれば準備完了です。

必要な jar ファイルは以下の 3 つです。

Java の Map(マップ)について

Jackson を使う前に、Java の「Map(マップ)」を紹介します。これまで学んだ ArrayList は「番号(添字)」でデータを管理しますが、Map は「名前(キー)」と「値」のペアでデータを管理します。
例えば、出席簿をイメージしてください

この構造は、JavaScript で学んだ「オブジェクト」にそっくりです。Map result = new HashMap<>(); と書くと、「文字列のラベル」に対して「文字列のデータ」を保存する箱ができあがります。 Map は、ArrayList では表現しにくい「任意のキーと値のセット」を JSON として返したいときに役立ちます。具体的な使い方は次節のサンプルコードで確認しましょう。

ポイント

  • Jackson の jar ファイルは Eclipse プロジェクトの src/main/webapp/WEB-INF/lib に配置する。
  • Java の Map は JavaScript のオブジェクトに相当するデータ構造で、キーと値のペアでデータを管理する。

13.1.3 Jackson ライブラリの使用

Jackson の基本的な使い方

import com.fasterxml.jackson.databind.ObjectMapper;

// オブジェクトを JSON に変換
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(オブジェクト);

// JSON をオブジェクトに変換
オブジェクト型 obj = mapper.readValue(json, オブジェクト型.class);

Mapを使ったJSON返却の例

前節に記載したObjectMapperとMapを使って、実際にJSONを返却するサーブレットのサンプルコードを見てみましょう。

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

Map<String, String> result = new HashMap<>();
result.put("status", "success");
result.put("message", "登録処理が完了しました。");

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(result);
// → {"status":"success","message":"登録処理が完了しました。"}

Map の put() メソッドは、JavaScriptの obj[“キー”] = “値” と同じ役割です。
上の例では「status」と「message」という2つのキーに、それぞれ文字列の値を保存しています。このパターンは、サーブレットからの「成功/失敗」の通知に使います。
一方、この後のサンプルコードで扱うArrayList+DTOクラスのパターンは、複数のデータを一覧で返す場合に使います。

13.1.4 サーブレットのサンプルコード

ここまでに紹介したObjectMapperを使って、実際にJSONを返却するサーブレットのサンプルコードを見てみましょう。以下のサンプルでは、ArrayList + DTOクラスパターンを扱います。

プロジェクト名:javascript_basic_webapi ※「動的 Web プロジェクト」として作成

ソースフォルダ:src/main/java/

パッケージ名:servlet

ファイル名:User.java, UserListServlet.java

アクセス URL:http://localhost:8080/javascript_basic_webapi/api/users

プロジェクト構成

javascript_basic_webapi/
├── src/main/java/
│   └── servlet/
│       ├── User.java
│       └── UserListServlet.java
└── src/main/webapp/
    ├── WEB-INF/
    │   └── lib/
    │       ├── jackson-annotations-2.20.jar
    │       ├── jackson-core-2.20.1.jar
    │       └── jackson-databind-2.20.1.jar
    ├── index.html
    └── js/
        └── app.js

User.java(モデルクラス)

package servlet;

public class User {
    private int id;
    private String name;
    private int age;

    // コンストラクタ
    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    // ゲッター(Jacksonが自動的にプロパティとして認識)
    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

UserListServlet.java

package servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import com.fasterxml.jackson.databind.ObjectMapper;

@WebServlet("/api/users")
public class UserListServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 1. ユーザーリストを準備(通常はDBから取得)
        ArrayList<User> userList = new ArrayList<User>();
        userList.add(new User(1, "田中太郎", 25));
        userList.add(new User(2, "佐藤花子", 30));
        userList.add(new User(3, "鈴木一郎", 28));

        // 2. JacksonでJSON文字列に変換
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(userList);

        // 3. レスポンスのContent-Typeを設定
        response.setContentType("application/json; charset=UTF-8");

        // 4. JSON文字列をレスポンスに書き出す
        PrintWriter out = response.getWriter();
        out.print(json);
        out.flush();
    }
}

解説

15 行目の@WebServlet アノテーションで、このサーブレットが/api/users という URL で呼び出されるように設定しています。

15: @WebServlet("/api/users")

22 行目から 25 行目で、User オブジェクトのリストを準備しています。 実際のアプリケーションでは、ここでデータベースからデータを取得することが多いです。

22: ArrayList<User> userList = new ArrayList<User>();
23: userList.add(new User(1, "田中太郎", 25));
24: userList.add(new User(2, "佐藤花子", 30));
25: userList.add(new User(3, "鈴木一郎", 28));

28 行目と 29 行目で、Jackson ライブラリの ObjectMapper インスタンスを作成し、writeValueAsString メソッドで userList を JSON 文字列に変換しています。

28: ObjectMapper mapper = new ObjectMapper();
29: String json = mapper.writeValueAsString(userList);

※変換後の JSON 文字列は以下のようになります:

[
    {"id":1,"name":"田中太郎","age":25},
    {"id":2,"name":"佐藤花子","age":30},
    {"id":3,"name":"鈴木一郎","age":28}
]

32 行目で、レスポンスの Content-Type を application/json に、文字エンコーディングを UTF-8 に設定しています。 これにより、ブラウザ側でレスポンスが JSON 形式であることを認識できます。

32: response.setContentType("application/json; charset=UTF-8");

35 行目から 37 行目で、JSON 文字列をレスポンスに書き出しています。

35: PrintWriter out = response.getWriter();
36: out.print(json);
37: out.flush();

Tomcat を起動して、作成した UserListServlet の URL にブラウザからアクセスしてみましょう。以下のように JSON 形式のレスポンスが返却されるようになっているかと思います。