SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Spring Bootで作るマイクロサービス

Spring Bootでバックエンドシステムを作成しよう

Spring Bootで作るマイクロサービス 第6回


  • X ポスト
  • このエントリーをはてなブックマークに追加

バックエンドでのデータ管理

 Apache Camelのおおよその流れがわかったところで、実際のデータを登録する処理を説明します。また、今回は利用する郵便番号データは、今回は日本郵便のHPからダウンロードしたものを利用しました。

[Note]日本郵便のHPからダウンロードできるデータについて

 日本郵便のHPからダウンロードできる郵便番号データは、自由に利用できますが、その場合には多少の注意が必要です。データ内の住所項目を見ると、「次のビルを除く」や、「以下に掲載がない場合」、複数の丁目「(1~3丁目)」や「(その他)」などのデータがあるので、これらのデータを実際に利用できる形に修正する必要があります。

 また、今回のサンプルのダウンロードURLに直接、日本郵便のHPのダウンロードURLを指定しないようにお願いします。

 サンプルのアプリケーションとコードの関係を示したものが図5になります。

図5:サンプルアプリケーションとサンプルコードでのクラスとの関係
図5:サンプルアプリケーションとサンプルコードでのクラスとの関係

 また、データ管理を行っているクラスは表2の機能が実装されています。

表2:データ登録・更新を実装しているクラス
クラス名 概要  
ZipcodeImportRouteBuilder Apache Camelのルート定義をするクラス
WebDownloadTask Springのスケジュール機能を利用した定期ファイル取得処理
AdminController ファイルアップロードを受け付けるRest API処理

フォルダを利用したデータ登録・更新

 指定したフォルダにファイルが存在すれば、そのファイルを検知し自動的に郵便番号データとしてデータベースに登録する流れにします。その処理のサンプルコードがリスト3です。

 この処理は、FTPやSCPなどによってデータが送信されてきて、指定のフォルダにアップロードが終わったタイミングで処理が実行されることを期待しています。

[リスト3]Apache Camelでの処理定義(src/main/java/com/coltware/springboot/zipcode/camel/ZipcodeImportRouteBuilder.javaの抜粋)
@Component
public class ZipcodeImportRouteBuilder extends RouteBuilder {
    : (省略)

    @Override
    public void configure() throws Exception {
        File file = new File(".");

        // (1) 実行しているフォルダ以下のimportフォルダをチェックする
        from("file://" + file.getAbsolutePath() + File.pathSeparator + "import").process((Exchange exchange) -> {
            File importFile = exchange.getIn().getBody(File.class);
            InputStream is = new FileInputStream(importFile);

            // (2) 次処理の入力データを設定する
            Message in = exchange.getIn();
            in.setBody(is);
        }).to("direct:import");

        //  (3) InputStreamの入力を受けてデータを登録するルート
        from("direct:import").process((Exchange exchange) -> {
            Message msg = exchange.getIn();
            Object body = msg.getBody();
            if(body instanceof InputStream){
               InputStream is = (InputStream)body;
               try {
                   importData(is);
                   exchange.getOut().setHeader("Status","OK");
               }
               // (省略)
            }
        });
    }

    // (3)
    protected void importData(InputStream is) throws UnsupportedEncodingException, IOException{
        // (省略) InputStreamからCSVデータを読んで、DBに追加、または更新する
    }
}

 (1)の"file://..."というエンドポイントのURI内に検知する際のフォルダを指定します。指定したフォルダにファイルが存在すれば自動で処理が実行されます。

 (2)では、次の処理の入力データとしてInputStreamのインスタンスを設定しています。入力時のオブジェクト型は自由なので、データを受ける処理側で型を意識する必要があります。

 (3)の"direct:<任意の名前>"というエンドポイントは、何も処理が行われないまま、次の処理に進みます。この名前を使って他の処理から自由にこの処理を呼び出すことができます。また、(3)は実際のCSVデータを読み取り、データベースに登録する処理です。実際のコードは添付するサンプルコードを参照してください。

定期スケジュールでデータを取得する

 続いて、定期的なスケジュールで外部のWebサイトにあるデータを取得し、データベースに登録・更新する処理を想定します。定期的なスケジュールや、外部のWebサイトからデータを取得することもApache Camelで記述が行えますが、今回はSpringでのスケジュール機能を利用します。

 Spring Bootでスケジュール機能を利用する場合には、リスト4のように@EnableSchedulingアノテーションを宣言する必要があります。

[リスト4]@EnableSchedulingアノテーションの宣言(src/main/java/com/coltware/springboot/zipcode/MainApplication.javaの抜粋)
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
public class MainApplication {
    // (省略)
}

 また、スケジュールとして実行される処理は@Scheduledアノテーションをメソッドに宣言し処理を記述します。

 リスト5は、Springのスケジュール機能を利用し、Apache Camelのルート処理を実行する際のサンプルコードです。

[リスト5]スケジュール処理の実装(src/main/java/com/coltware/springboot/zipcode/task/WebDownloadTask.javaの抜粋)
: (省略)
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class WebDownloadTask {

    // (1) Apache CamelのContextオブジェクトを取得する
    @Autowired
    CamelContext camelContext;

    // (2) Springのスケジュール機能を使った実行
    @Scheduled(cron = "0 0 1 * * *")
    public void downloadFile(){

        // (3) 指定したURLからファイルをダウンロードする
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder(URI.create(downloadUrl)).build();

        try {
            Path path = Files.createTempFile("download-",".zip");

            HttpResponse<Path> response = client.send(request, HttpResponse.BodyHandlers.ofFile(path));
            File file = path.toFile();
            if(file.exists()){

                ZipFile zipFile = new ZipFile(file);
                ZipEntry entry = zipFile.entries().nextElement();
                InputStream is = zipFile.getInputStream(entry);

                // (4) ダウンロードしたZipファイル内のデータ(1つのみ)を入力とし、"direct:import"のエンドポイントに処理をつなげる
                ProducerTemplate template = camelContext.createProducerTemplate();
                Exchange exchange = template.send("direct:import", (Exchange obj) -> {
                    obj.getIn().setBody(is,InputStream.class);
                });

                // (5) 処理結果を取得する
                Message out = exchange.getOut();
                String status = out.getHeader("status",String.class);
                if(status.equals("OK")){
                    log.info("import OK");
                }
                // (省略)
            }
        }
        // (省略)
    }
}

 (1)では、Apache CamelのContextオブジェクトを取得します。Apache Camelの外から処理を実行する場合にはこのオブジェクトを取得します。また、このオブジェクトはSpring Boot側で自動的に作成されています。

 (2)では実行するスケジュール処理を記述しています。また、サンプルではスケジュールはcron形式での記述が可能であり、ここでは毎月1日の00:00に処理を実行するように指定しています。今回使用したcron表記方法以外にも表3の表記方法があり、cron以外の表記方法はTimerクラスを使ったスケジュール実行と同じルールになります。

 (3)では指定したURLからファイルをダウンロードしています。ダウンロードするファイルはZip圧縮されている前提としています。続いて、(4)では(3)で取得したデータを利用し、Apache Camel側で作成した"direct:import"というエンドポイントに入力を渡します。

 このようにApache Camelの"direct"というスキームは、外部のプログラムからも実行できるので非常に便利です。

 処理の結果を取得したい場合には、(5)のようにして結果を取得することもできます。

表3:@Scheduledに記述できるパラメータ一覧
クラス名 概要 
cron cronでの記述方法と同じように記述可能
fixedDelay  前の処理と次の処理の間隔が指定したミリ秒になるように処理が実行される
fixedRate 指定したミリ秒間隔で処理が定期的に実行される。処理開始の間隔になるので処理自体が長い場合には、同時に2つ以上の処理が実行される場合がある
initialDelay 最初の処理を行うための待機時間

HTTPを使った、ファイルのアップロード処理からのデータ登録

 HTTPのPUTを使ったファイルアップロードを使ってデータを登録する場合では、これまでの例と前回までのRestControllerの知識があれば実装可能です。

 詳しい説明は割愛しますが、リスト5のコードで実装できます。

[リスト5]Rest処理からのApache Camelのルート実行(src/main/java/com/coltware/springboot/zipcode/controller/AdminController.javaの抜粋)
@RequestMapping("/admin/zipcode")
public class AdminController {

    //  PUTでのファイルアップロード処理
    //  curlを使ったファイルアップロード例 : curl -u  -X PUT http://127.0.0.1:8082/admin/zipcode/import -T import.csv
    @PutMapping("/import")
    public Response importAction(InputStream is){
        // 受信したデータを使ってApache Camelのルートを実行する
        ProducerTemplate template = camelContext.createProducerTemplate();
        Exchange exchange = template.send("direct:import", (Exchange obj) -> {
            obj.getIn().setBody(is,InputStream.class);
        });
        // (省略)
    }
}

最後に

 Spring Bootを使う理由の1つとして、TomcatなどのWebコンテナとSpring Frameworkという使い方だけではなく、今回のサンプルアプリケーションのように、Webだけではない別のフレームワークとWebフレームワークを混在させた1つのアプリケーションが作りやすい点があげられます。

 また、Webシステムだけであれば、PHPやRuby、Pythonといったスクリプト系の言語の方が使いやすい場合がありますが、今回のようなHTTP以外での入出力データをカバーする必要が生じた場合にJavaという言語の強みがより一層引き立つはずです。

 次回は、今回作成したサンプルアプリケーションに認証をつける方法や、細かなSpring Bootの設定カスタマイズなどを紹介します。

参考資料

 

本連載の書籍が発売されました!

Javaによる高速Webアプリケーション開発のためのSpring Boot入門

Amazon(POD) Amazon(電子書籍) その他

Javaによる高速Webアプリケーション開発のためのSpring Boot入門

著者:WINGSプロジェクト 小林昌弘
発売日:2020年5月31日(水)
価格(POD):2,200円(税込)
価格(電書):1,760円(税込)

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Spring Bootで作るマイクロサービス連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/11673 2020/06/01 19:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング