[Java]Spring BootでのLINE連携


## はじめに
現在アサインされている案件で、Spring Boot上でのLINE連携(LINE BOT)を行っております。
内容が面白いと感じましたので、今回別途調査・実装してみました。

## LINE連携(LINE BOT)について
LINE BOTは「LINE Messaging API」の通称で、ユーザと自動的にメッセージのやり取りを行うことできるAPIです。
主な機能は以下の通りとなります。

|機能|概要|
|:---:|:---:|
|Push API|BOT起点でメッセージを送る機能|
|Reply API|ユーザからのメッセージ起点でメッセージを送る機能|
![line_message_api.png](https://qiita-image-store.s3.amazonaws.com/0/215568/ac7c2093-4627-47da-99e1-e6a364ed04c6.png)

## 開発環境
・STS(Spring Tool Suite) ※ 単体パッケージ版
・JDK1.8
・Heroku

## LINE BOTの動作確認(前準備)
### 1.「LINE Developers」への登録
LINE BOTを利用するためには、「[LINE Developers](https://developers.line.biz/ja/　"LINE Developers")」への登録が必要となります。
必要なものはLINEアカウントのみとなります。

<登録手順>
1 .  赤枠の「ログイン」ボタンを押下する。
![line_develop_1.PNG](https://qiita-image-store.s3.amazonaws.com/0/215568/a47c9be7-12ce-abb3-0c71-07ab0f5edf55.png)

2 . LINEアカウントでログインする。
![line_develop_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/215568/33d5e46a-9093-3878-e547-c79c691bec92.png)

3 . 開発者情報(開発者名/メールアドレス)を入力する。
![line_develop_3.png](https://qiita-image-store.s3.amazonaws.com/0/215568/45f4e37d-48e6-255f-fe97-2fd94a5e8545.png)

4 . 入力内容に問題がなければアカウントを作成します。
![line_develop_4.png](https://qiita-image-store.s3.amazonaws.com/0/215568/410e5454-3acb-7a41-4871-9c717dc199b7.png)

### 2.プロバイダーの新規作成
プロバイダーは、サービス提供者（企業・個人）の名前です。

<作成手順>
1 .  赤枠の「新規プロバイダー作成」ボタンを押下する。
![line_develop_5.png](https://qiita-image-store.s3.amazonaws.com/0/215568/877eade7-73f4-e57f-186f-b57427fc2041.png)

2 . プロバイダー名を入力する。
![line_develop_6.png](https://qiita-image-store.s3.amazonaws.com/0/215568/d97cde44-83f1-c4f1-aeed-af60b78dcf6f.png)

3 . 入力内容に問題がなければプロバイダーを作成します。
![line_develop_7.png](https://qiita-image-store.s3.amazonaws.com/0/215568/ed966f6a-3f22-eb43-d94f-154e6433adbc.png)

### 3.チャネル(BOT)の新規作成
チャネルには「LINEログイン」「Message API」「Clovaスキル」と3つありますが、
今回は「Message API」のチャネルを作成します。

<作成手順>
1 .  赤枠の「チャネル作成する」ボタンを押下する。
![line_develop_8.png](https://qiita-image-store.s3.amazonaws.com/0/215568/491809c6-e32d-98e6-4d22-7bc230471ea8.png)

2 .  以下のアプリケーション情報を入力する。
・アプリアイコン画像
・アプリ名
・アプリ説明文
・プラン(テストするだけなら「Developer Trial」を使用)
・大業種
・小業種
・お知らせ通知用メールアドレス(特に指定がなければ、アカウント登録時のメールアドレスを指定)
![line_develop_9.png](https://qiita-image-store.s3.amazonaws.com/0/215568/82f7c21b-4e27-5657-6a54-5dcba5087445.png)

3 . 入力内容に問題がなければチャネルを作成します。
![line_develop_10.png](https://qiita-image-store.s3.amazonaws.com/0/215568/07ff185b-7aeb-6ada-41b6-7f8137ccb6c5.png)

```math
\def\textlarge#1{%
   {\rm\Large #1}
}
\def\textsmall#1{%
  {\rm\scriptsize #1}
}
```
### 4.動作確認
今回は、以下のメッセージの応答を確認します。

|メッセージ|概要|
|:------------:|:------------:|
|$\textsmall{キーワード応答メッセージ}$|$\textsmall{特定のキーワードが入力された場合に自動的に送信されるメッセージ}$|
|$\textsmall{自動応答メッセージ}$|$\textsmall{キーワード応答メッセージ以外が入力された場合に自動的に送信されるメッセージ}$|

<確認手順>
1 .  赤枠の作成したチャネルを押下する。
![line_develop_11.png](https://qiita-image-store.s3.amazonaws.com/0/215568/754b127c-9019-703b-5e81-f39ca2c7a692.png)

2 .  赤枠のリンクから「LINE管理画面」へ遷移する。
![line_develop_12.png](https://qiita-image-store.s3.amazonaws.com/0/215568/e466e7f4-336d-7248-d668-7410c7f7a337.png)

3 . LINE管理画面のメッセージメニューより、キーワード応答メッセージを作成する。
今回は、「テスト」をキーワードに作成しました。
![line_develop_13.png](https://qiita-image-store.s3.amazonaws.com/0/215568/152b2573-bc0a-5fcf-315e-c2dc553c5f5f.png)

4 . LINE管理画面のメッセージメニューより、自動応答メッセージを作成する。
![line_develop_14.png](https://qiita-image-store.s3.amazonaws.com/0/215568/57d63cb6-7c09-b6d5-68d0-625cea4d21c1.png)

5 . 実際にメッセージ応答を確認する。
※　BOTの友達追加は「LINEアプリへのQRコード」を読み込む等して追加します。
![line_develop_15.png](https://qiita-image-store.s3.amazonaws.com/0/215568/3e3e6e65-43fb-19f9-f5cf-2117c5f4e79e.png)

## Spring BootのLINE連携
前準備が長くなりましたが、ここからが本題です。
Spring BootのLINE連携部分を実装します。

### 1. 依存関係の追加
今回は、Mavenを使用しているのでpom.xmlに以下の依存関係を追加します。

```XML:pom.xml
	<dependency>
            <groupId>com.linecorp.bot</groupId>
            <artifactId>line-bot-spring-boot</artifactId>
            <version>2.0.0</version>
    </dependency>
```

### 2. プロパティ追加
プロパティファイルに以下のプロパティを追加します。
「channel-token」と「channel-secret」は、作成したBOTのチャネル基本設定に記載されています。
「channel-token」に関しては、初回は作成されていないので再発行が必要となります。

```YAML:application.yml
line: 
  bot:
    channel-token: 「アクセストークン（ロングターム）」欄の文字列
    channel-secret: 「Channel Secret」欄の文字列
    handler.path: /callback
```

### 3. アプリケーションクラスの修正
アプリケーションクラスにLINEメッセージ受信時の処理を追加します。
「[line-bot-sdk](https://github.com/line/line-bot-sdk-java/tree/master/line-bot-spring-boot "line-bot-sdk")」のサンプルを基に作成します。
LINEの送信メッセージをそのまま返す仕様です。

```java:SpringBootResearchApplication.java
package spring.research;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.linecorp.bot.model.event.Event;
import com.linecorp.bot.model.event.MessageEvent;
import com.linecorp.bot.model.event.message.TextMessageContent;
import com.linecorp.bot.model.message.TextMessage;
import com.linecorp.bot.spring.boot.annotation.EventMapping;
import com.linecorp.bot.spring.boot.annotation.LineMessageHandler;

/**
 * アプリケーションクラス
 * @author s-tsuchida
 */
@SpringBootApplication
@LineMessageHandler
public class SpringBootResearchApplication {

    public static void main(String[] args) {
		final SpringApplication springApplication = new SpringApplication(SpringBootResearchApplication.class);
		springApplication.run(args);
    }

    @EventMapping
    public TextMessage handleTextMessageEvent(MessageEvent<TextMessageContent> event) {
        System.out.println("event: " + event);
        return new TextMessage(event.getMessage().getText());
    }

    @EventMapping
    public void handleDefaultMessageEvent(Event event) {
        System.out.println("event: " + event);
    }
    
}

```

### 4. 作成したアプリケーションをHerokuにデプロイ
では、作成したアプリケーションをHerokuにデプロイして動作確認します。
Herokuの登録方法等は、以下のURLで分かりやすく説明されていましたので、こちらを参照してください。
・[LINE bot作ってみた詳細③〜LINE bot自作(2/2)](http://oasobi-program.hatenadiary.jp/entry/2017/04/13/001258 "LINE bot作ってみた詳細③〜LINE bot自作(2/2)")
![line_develop_16.png](https://qiita-image-store.s3.amazonaws.com/0/215568/3031874c-04a4-f5b2-a617-6e61adee7a9e.png)


## 【番外編】作ってみた
上記アプリケーションを基に、私が勤めている会社の経営理念・コアバリューを返してくれるように編集しました。
経営理念等の詳細が知りたい方は、以下のURLを参照してください。
・[株式会社アイエンター](https://www.i-enter.co.jp/about/ "株式会社アイエンター")

```java:SpringBootResearchApplication.java
package spring.research;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.linecorp.bot.model.event.Event;
import com.linecorp.bot.model.event.MessageEvent;
import com.linecorp.bot.model.event.message.TextMessageContent;
import com.linecorp.bot.model.message.TextMessage;
import com.linecorp.bot.spring.boot.annotation.EventMapping;
import com.linecorp.bot.spring.boot.annotation.LineMessageHandler;

import spring.research.domain.service.line.LineService;

/**
 * メインプログラム
 * @author s-tsuchida
 */
@SpringBootApplication
@LineMessageHandler
public class SpringBootResearchApplication {

	// LINEサービス
	@Autowired
	private LineService lineService;
	
    public static void main(String[] args) {
		final SpringApplication springApplication = new SpringApplication(SpringBootResearchApplication.class);
		springApplication.run(args);
    }

    @EventMapping
    public TextMessage handleTextMessageEvent(MessageEvent<TextMessageContent> event) {
    	System.out.println("event: " + event);
        return new TextMessage(lineService.createResponseMessage(event.getMessage().getText()));
    }

    @EventMapping
    public void handleDefaultMessageEvent(Event event) {
    	System.out.println("event: " + event);
    }
    
}
```

```java:LineService.java
package spring.research.domain.service.line;

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

import org.springframework.stereotype.Component;


/**
 * LINEサービス
 * @author s-tsuchida
 */
@Component
public class LineService {

	// 返答メッセージ
	private static final String MISSION_MESSAGE = "楽しむを世界へ";
	private static final String PHILOSOPHY_MESSAGE = "信頼され愛される企業をめざし、\r\nたゆまぬ努力をしつづけます。\r\n"
			+ "一. 仕事を楽しむ\r\n"
			+ "一. 成長を楽しむ\r\n"
			+ "一. 挑戦を楽しむ\r\n"
			+ "一. サービスを楽しむ\r\n"
			+ "一. 感謝を楽しむ\r\n";
	private static final String CORE_VALUE_01_MESSAGE = "1.常に前向きに行動しよう";
	private static final String CORE_VALUE_02_MESSAGE = "2.何事にも一生懸命、一所懸命やろう";
	private static final String CORE_VALUE_03_MESSAGE = "3.日本一のマナーを実践しよう";
	private static final String CORE_VALUE_04_MESSAGE = "4.NO.1をつくろう";
	private static final String CORE_VALUE_05_MESSAGE = "5.スピードを追求し喜びを与えよう";
	private static final String CORE_VALUE_06_MESSAGE = "6.全ての人にワクワクを仕掛けよう";
	private static final String CORE_VALUE_07_MESSAGE = "7.自分力を磨こう";
	private static final String CORE_VALUE_08_MESSAGE = "8.素直で謙虚になろう";
	private static final String CORE_VALUE_09_MESSAGE = "9.家族のようなチームをつくろう";
	private static final String CORE_VALUE_10_MESSAGE = "10.夢・希望を強く思い続け現実にしよう";
	private static final String CORE_VALUE_ALL_MESSAGE = CORE_VALUE_01_MESSAGE + "\r\n"
			+ CORE_VALUE_02_MESSAGE + "\r\n"
			+ CORE_VALUE_03_MESSAGE + "\r\n"
			+ CORE_VALUE_04_MESSAGE + "\r\n"
			+ CORE_VALUE_05_MESSAGE + "\r\n"
			+ CORE_VALUE_06_MESSAGE + "\r\n"
			+ CORE_VALUE_07_MESSAGE + "\r\n"
			+ CORE_VALUE_08_MESSAGE + "\r\n"
			+ CORE_VALUE_09_MESSAGE + "\r\n"
			+ CORE_VALUE_10_MESSAGE + "\r\n";
	
	// メッセージ該当外メッセージ
	private static final String OTHER_MESSAGE = "ようこそ!\r\nSpringLineBotへ!";
	
	// メッセージMAP
	private static final Map<String, String> MESSAGE_MAP = Collections.unmodifiableMap(new HashMap<String, String>(){
		private static final long serialVersionUID = 1L;
		
		{
			// ミッション
			put("misson", MISSION_MESSAGE);
			put("MISSION", MISSION_MESSAGE);
			put("ミッション", MISSION_MESSAGE);
			put("みっしょん", MISSION_MESSAGE);
			
			//　経営理念
			put("philosophy", PHILOSOPHY_MESSAGE);
			put("PHILOSOPHY", PHILOSOPHY_MESSAGE);
			put("けいえいりねん", PHILOSOPHY_MESSAGE);
			put("経営理念", PHILOSOPHY_MESSAGE);
			
			// コアバリュー1
			put("corevalue1", CORE_VALUE_01_MESSAGE);
			put("COREVALUE1", CORE_VALUE_01_MESSAGE);
			put("こあばりゅー1", CORE_VALUE_01_MESSAGE);
			put("コアバリュー1", CORE_VALUE_01_MESSAGE);
			
			// コアバリュー2
			put("corevalue2", CORE_VALUE_02_MESSAGE);
			put("COREVALUE2", CORE_VALUE_02_MESSAGE);
			put("こあばりゅー2", CORE_VALUE_02_MESSAGE);
			put("コアバリュー2", CORE_VALUE_02_MESSAGE);
			
			// コアバリュー3
			put("corevalue3", CORE_VALUE_03_MESSAGE);
			put("COREVALUE3", CORE_VALUE_03_MESSAGE);
			put("こあばりゅー3", CORE_VALUE_03_MESSAGE);
			put("コアバリュー3", CORE_VALUE_03_MESSAGE);
			
			// コアバリュー4
			put("corevalue4", CORE_VALUE_04_MESSAGE);
			put("COREVALUE4", CORE_VALUE_04_MESSAGE);
			put("こあばりゅー4", CORE_VALUE_04_MESSAGE);
			put("コアバリュー4", CORE_VALUE_04_MESSAGE);			
			
			// コアバリュー5
			put("corevalue5", CORE_VALUE_05_MESSAGE);
			put("COREVALUE5", CORE_VALUE_05_MESSAGE);
			put("こあばりゅー5", CORE_VALUE_05_MESSAGE);
			put("コアバリュー5", CORE_VALUE_05_MESSAGE);
			
			// コアバリュー6
			put("corevalue6", CORE_VALUE_06_MESSAGE);
			put("COREVALUE6", CORE_VALUE_06_MESSAGE);
			put("こあばりゅー6", CORE_VALUE_06_MESSAGE);
			put("コアバリュー6", CORE_VALUE_06_MESSAGE);
			
			// コアバリュー7
			put("corevalue7", CORE_VALUE_07_MESSAGE);
			put("COREVALUE7", CORE_VALUE_07_MESSAGE);
			put("こあばりゅー7", CORE_VALUE_07_MESSAGE);
			put("コアバリュー7", CORE_VALUE_07_MESSAGE);
			
			// コアバリュー8
			put("corevalue8", CORE_VALUE_08_MESSAGE);
			put("COREVALUE8", CORE_VALUE_08_MESSAGE);
			put("こあばりゅー8", CORE_VALUE_08_MESSAGE);
			put("コアバリュー8", CORE_VALUE_08_MESSAGE);
			
			// コアバリュー9
			put("corevalue9", CORE_VALUE_09_MESSAGE);
			put("COREVALUE9", CORE_VALUE_09_MESSAGE);
			put("こあばりゅー9", CORE_VALUE_09_MESSAGE);
			put("コアバリュー9", CORE_VALUE_09_MESSAGE);
			
			// コアバリュー10
			put("corevalue10", CORE_VALUE_10_MESSAGE);
			put("COREVALUE10", CORE_VALUE_10_MESSAGE);
			put("こあばりゅー10", CORE_VALUE_10_MESSAGE);
			put("コアバリュー10", CORE_VALUE_10_MESSAGE);
			
			// コアバリューすべて
			put("corevalue", CORE_VALUE_ALL_MESSAGE);
			put("COREVALUE", CORE_VALUE_ALL_MESSAGE);
			put("こあばりゅー", CORE_VALUE_ALL_MESSAGE);
			put("コアバリュー", CORE_VALUE_ALL_MESSAGE);
			
		}
	});

	/**
	 * 送信されたLINEメッセージをもとに返答メッセージを返す
	 * @param sendMessage 送信されたLINEメッセージ
	 * @return 返答メッセージ
	 */
	public String createResponseMessage(String sendMessage) {
		
		if(MESSAGE_MAP.containsKey(sendMessage)) {
			// 送信されたLINEメッセージがMAPのキーに存在する場合
			return MESSAGE_MAP.get(sendMessage);
		} else {
			// 送信されたLINEメッセージがMAPのキーに存在しない場合
			return  OTHER_MESSAGE;
		}
	}
	
}

```

![line_develop_17.png](https://qiita-image-store.s3.amazonaws.com/0/215568/618b9922-401c-4af4-b127-e67980791732.png)

## まとめ
既存のサービスとの連携はあまり経験がなかったので新鮮で面白く感じました。
今後は、cronを用いて定期的にLINEメッセージを送る等も試してみたいと思います。

## 参考にしたサイト
・[おあそび ぷろぐらみんぐ 日記](http://oasobi-program.hatenadiary.jp/archive/category/LINE%20bot "おあそび ぷろぐらみんぐ 日記")
・[Spring BootとLINE Messaging APIで作ったLINE BOTをHerokuで動かす](http://kikutaro777.hatenablog.com/entry/2017/01/16/230122 "Spring BootとLINE Messaging APIで作ったLINE BOTをHerokuで動かす")
・[ごみ収集日前にアラートを出すLINEbot](https://aytdm.com/2017/10/31/12/ "ごみ収集日前にアラートを出すLINEbot")