LINE Messaging APIをSpringBoot(on Heroku)で試す

More than 1 year has passed since last update.


はじめに

LINE Messaging APIをSpringBootで実装するSDKが公式からでていたので試す。

LINE Messaging APIは、httpsでの通信が前提なので、Herokuにアプリケーションをデプロイ(無料)してテストする。


手順

基本的には、公式SDKのgithubのマニュアルのとおり実施しますが、botの内容を発言したユーザーのユーザーIDを返信する処理にしました。

自分のLINEのユーザーIDを知る術がわからなかったので、replyのメッセージから取得したかったというのもあります。

※詳しい人は教えてください。


  1. SpringBootのプロジェクトを作成

  2. LINE Messaging APIの公式SDKのline-bot-spring-bootをgradleの依存に追加

  3. sampleを参考にSpringBootの起動クラスにコードを追加

  4. Herokuにデプロイ

  5. LINE Messaging APIのMessaging API Developer Trialアカウントを追加(もろもろの設定とシークレットとトークンを取得)

  6. Herokuの設定にシークレットとトークンを設定

  7. 動作確認


詳細


SpringBootのプロジェクトを作成

以下の記事を参考にSpringBootの雛形プロジェクトを作成

Spring BootをHerokuにデプロイするのが劇的に簡単になっている件

※Herokuにアプリケーションデプロイするところまで実施する


LINE Messaging APIの公式SDKをgradleの依存に追加

build.gradleのdependenciesに以下を追加

dependencies {

compile('com.linecorp.bot:line-bot-spring-boot:1.3.0') // ココを追加
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
}


sampleを参考にSpringBootの起動クラスにコード追加

公式SDKのsample実装を参考に以下のようにSpringBootの起動クラスを修正

サンドイッチコメントで修正箇所を記載しています。クラスにも@LineMessageHandlerアノテーションを付けるのをわすれずに。

importはsampleを参考にしてください。

package com.example;

import com.linecorp.bot.client.LineMessagingService;
import com.linecorp.bot.model.ReplyMessage;
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.model.response.BotApiResponse;
import com.linecorp.bot.spring.boot.annotation.EventMapping;

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

import java.util.Collections;

@SpringBootApplication
@LineMessageHandler //----- ココを追加
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

//----- ここから -----
@Autowired
private LineMessagingService lineMessagingService;

@EventMapping
public void handleTextMessageEvent(MessageEvent<TextMessageContent> event) throws Exception {
System.out.println("event: " + event);
final BotApiResponse apiResponse = lineMessagingService
.replyMessage(new ReplyMessage(event.getReplyToken(),
Collections.singletonList(new TextMessage(event.getSource().getUserId()))))
.execute().body();
System.out.println("Sent messages: " + apiResponse);
}

@EventMapping
public void defaultMessageEvent(Event event) {
System.out.println("event: " + event);
}
//----- ここまで追加 -----

}


Herokuにデプロイ

git commit -am "add line bot"

git push heroku master

デプロイは成功するはず。Herokuのログを確認すると、

heroku logs --tail

以下のエラーが発生する


抜粋

2016-11-23T12:34:48.860128+00:00 app[web.1]: Field error in object 'line.bot' on field 'channelToken': rejected value [null]; codes [NotNull.line.bot.channelToken,NotNull.channelToken,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [line.bot.channelToken,channelToken]; arguments []; default message [channelToken]]; default message [may not be null]

2016-11-23T12:34:48.860129+00:00 app[web.1]: Field error in object 'line.bot' on field 'channelSecret': rejected value [null]; codes [NotNull.line.bot.channelSecret,NotNull.channelSecret,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [line.bot.channelSecret,channelSecret]; arguments []; default message [channelSecret]]; default message [may not be null]


全体

2016-11-23T12:34:25.585995+00:00 heroku[web.1]: Starting process with command `java -Dserver.port=26054 $JAVA_OPTS -jar build/libs/*.jar`

2016-11-23T12:34:28.350814+00:00 app[web.1]: Create a Procfile to customize the command used to run this process: https://devcenter.heroku.com/articles/procfile
2016-11-23T12:34:28.363096+00:00 app[web.1]: Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.
2016-11-23T12:34:28.370890+00:00 app[web.1]: Picked up JAVA_TOOL_OPTIONS: -Xmx350m -Xss512k -Dfile.encoding=UTF-8
2016-11-23T12:34:33.611174+00:00 app[web.1]:
2016-11-23T12:34:33.611223+00:00 app[web.1]: . ____ _ __ _ _
2016-11-23T12:34:33.611274+00:00 app[web.1]: /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
2016-11-23T12:34:33.611327+00:00 app[web.1]: ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
2016-11-23T12:34:33.611374+00:00 app[web.1]: \\/ ___)| |_)| | | | | || (_| | ) ) ) )
2016-11-23T12:34:33.611423+00:00 app[web.1]: ' |____| .__|_| |_|_| |_\__, | / / / /
2016-11-23T12:34:33.611471+00:00 app[web.1]: =========|_|==============|___/=/_/_/_/
2016-11-23T12:34:33.616715+00:00 app[web.1]: :: Spring Boot :: (v1.4.2.RELEASE)
2016-11-23T12:34:33.616758+00:00 app[web.1]:
2016-11-23T12:34:35.077856+00:00 app[web.1]: 2016-11-23 12:34:35.043 INFO 4 --- [ main] com.example.DemoApplication : Starting DemoApplication on 3fec34e1-1683-4668-b572-8d779c0b0d2a with PID 4 (/app/build/libs/demo-0.0.1-SNAPSHOT.jar started by u52915 in /app)
2016-11-23T12:34:35.099269+00:00 app[web.1]: 2016-11-23 12:34:35.078 INFO 4 --- [ main] com.example.DemoApplication : No active profile set, falling back to default profiles: default
2016-11-23T12:34:35.786319+00:00 app[web.1]: 2016-11-23 12:34:35.770 INFO 4 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6659c656: startup date [Wed Nov 23 12:34:35 UTC 2016]; root of context hierarchy
2016-11-23T12:34:45.729917+00:00 app[web.1]: 2016-11-23 12:34:45.729 INFO 4 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 26054 (http)
2016-11-23T12:34:45.758893+00:00 app[web.1]: 2016-11-23 12:34:45.758 INFO 4 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2016-11-23T12:34:45.761198+00:00 app[web.1]: 2016-11-23 12:34:45.760 INFO 4 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.6
2016-11-23T12:34:46.348214+00:00 app[web.1]: 2016-11-23 12:34:46.346 INFO 4 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2016-11-23T12:34:46.349784+00:00 app[web.1]: 2016-11-23 12:34:46.349 INFO 4 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 10608 ms
2016-11-23T12:34:48.252663+00:00 app[web.1]: 2016-11-23 12:34:48.252 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2016-11-23T12:34:48.290693+00:00 app[web.1]: 2016-11-23 12:34:48.290 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'metricsFilter' to: [/*]
2016-11-23T12:34:48.291348+00:00 app[web.1]: 2016-11-23 12:34:48.291 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2016-11-23T12:34:48.291501+00:00 app[web.1]: 2016-11-23 12:34:48.291 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2016-11-23T12:34:48.291646+00:00 app[web.1]: 2016-11-23 12:34:48.291 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2016-11-23T12:34:48.291783+00:00 app[web.1]: 2016-11-23 12:34:48.291 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2016-11-23T12:34:48.291919+00:00 app[web.1]: 2016-11-23 12:34:48.291 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'webRequestLoggingFilter' to: [/*]
2016-11-23T12:34:48.292078+00:00 app[web.1]: 2016-11-23 12:34:48.291 INFO 4 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'applicationContextIdFilter' to: [/*]
2016-11-23T12:34:48.852189+00:00 app[web.1]: 2016-11-23 12:34:48.851 ERROR 4 --- [ main] o.s.b.b.PropertiesConfigurationFactory : Properties configuration failed validation
2016-11-23T12:34:48.852531+00:00 app[web.1]: 2016-11-23 12:34:48.852 ERROR 4 --- [ main] o.s.b.b.PropertiesConfigurationFactory : Field error in object 'line.bot' on field 'channelToken': rejected value [null]; codes [NotNull.line.bot.channelToken,NotNull.channelToken,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [line.bot.channelToken,channelToken]; arguments []; default message [channelToken]]; default message [may not be null]
2016-11-23T12:34:48.856823+00:00 app[web.1]: 2016-11-23 12:34:48.852 ERROR 4 --- [ main] o.s.b.b.PropertiesConfigurationFactory : Field error in object 'line.bot' on field 'channelSecret': rejected value [null]; codes [NotNull.line.bot.channelSecret,NotNull.channelSecret,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [line.bot.channelSecret,channelSecret]; arguments []; default message [channelSecret]]; default message [may not be null]
2016-11-23T12:34:48.860126+00:00 app[web.1]: 2016-11-23 12:34:48.859 WARN 4 --- [ main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoApplication': Unsatisfied dependency expressed through field 'lineMessagingService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.linecorp.bot.spring.boot.LineBotAutoConfiguration': Unsatisfied dependency expressed through field 'lineBotProperties'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'line.bot-com.linecorp.bot.spring.boot.LineBotProperties': Could not bind properties to LineBotProperties (prefix=line.bot, ignoreInvalidFields=false, ignoreUnknownFields=true, ignoreNestedProperties=false); nested exception is org.springframework.validation.BindException: org.springframework.boot.bind.RelaxedDataBinder$RelaxedBeanPropertyBindingResult: 2 errors
2016-11-23T12:34:48.860128+00:00 app[web.1]: Field error in object 'line.bot' on field 'channelToken': rejected value [null]; codes [NotNull.line.bot.channelToken,NotNull.channelToken,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [line.bot.channelToken,channelToken]; arguments []; default message [channelToken]]; default message [may not be null]
2016-11-23T12:34:48.860129+00:00 app[web.1]: Field error in object 'line.bot' on field 'channelSecret': rejected value [null]; codes [NotNull.line.bot.channelSecret,NotNull.channelSecret,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [line.bot.channelSecret,channelSecret]; arguments []; default message [channelSecret]]; default message [may not be null]
2016-11-23T12:34:48.864487+00:00 app[web.1]: 2016-11-23 12:34:48.864 INFO 4 --- [ main] o.apache.catalina.core.StandardService : Stopping service Tomcat
2016-11-23T12:34:49.049475+00:00 app[web.1]: 2016-11-23 12:34:49.047 INFO 4 --- [ main] utoConfigurationReportLoggingInitializer :
2016-11-23T12:34:49.049477+00:00 app[web.1]:
2016-11-23T12:34:49.049478+00:00 app[web.1]: Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2016-11-23T12:34:49.142077+00:00 app[web.1]: 2016-11-23 12:34:49.141 ERROR 4 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
2016-11-23T12:34:49.142090+00:00 app[web.1]:
2016-11-23T12:34:49.142091+00:00 app[web.1]: ***************************
2016-11-23T12:34:49.142092+00:00 app[web.1]: APPLICATION FAILED TO START
2016-11-23T12:34:49.142092+00:00 app[web.1]: ***************************
2016-11-23T12:34:49.142093+00:00 app[web.1]:
2016-11-23T12:34:49.142094+00:00 app[web.1]: Description:
2016-11-23T12:34:49.142094+00:00 app[web.1]:
2016-11-23T12:34:49.142095+00:00 app[web.1]: Binding to target LineBotProperties(channelToken=null, channelSecret=null, apiEndPoint=https://api.line.me/, connectTimeout=10000, readTimeout=10000, writeTimeout=10000, handler=LineBotProperties.Handler(enabled=true, path=/callback)) failed:
2016-11-23T12:34:49.142096+00:00 app[web.1]:
2016-11-23T12:34:49.142097+00:00 app[web.1]: Property: line.bot.channelToken
2016-11-23T12:34:49.142097+00:00 app[web.1]: Value: null
2016-11-23T12:34:49.142098+00:00 app[web.1]: Reason: may not be null
2016-11-23T12:34:49.142098+00:00 app[web.1]:
2016-11-23T12:34:49.142099+00:00 app[web.1]: Property: line.bot.channelSecret
2016-11-23T12:34:49.142100+00:00 app[web.1]: Value: null
2016-11-23T12:34:49.142100+00:00 app[web.1]: Reason: may not be null
2016-11-23T12:34:49.142101+00:00 app[web.1]:
2016-11-23T12:34:49.142102+00:00 app[web.1]:
2016-11-23T12:34:49.142102+00:00 app[web.1]: Action:
2016-11-23T12:34:49.142103+00:00 app[web.1]:
2016-11-23T12:34:49.142103+00:00 app[web.1]: Update your application's configuration
2016-11-23T12:34:49.142104+00:00 app[web.1]:
2016-11-23T12:34:49.346537+00:00 heroku[web.1]: Process exited with status 1
2016-11-23T12:34:49.361013+00:00 heroku[web.1]: State changed from starting to crashed

エラーになってもここまでくればOK


LINE Messaging APIのアカウントを追加

まず、LINE BUSINESS CENTERでアカウント登録が必要かもしれないので、未登録の人は登録してください。メールアドレスとパスワードを入れて認証(LINEに4桁のコードが送られてくる)するだけです。

また、公式のドキュメントにわかりやすい動画(36秒)があるのでそれを見たほうが早いかもしれません。

Messaging APIのページの「Develper Trialを始める」のボタンをクリック

image

アカウントの作成画面がでるので、アカウント名に適当な名前と、業種を適当に選択し、「確認する」ボタンをクリック

image

確認画面に遷移するので「申し込む」ボタンをクリック

image

以下の画面に遷移するので、「LINE@MANAGERへ」のボタンをクリック

image

Bot設定の画面に遷移するので「APIを利用する」ボタンをクリック

image

再度注意事項が確認されるので「確認」をクリック

image

「成功しました」のメッセージがでるので「OK」ボタンをクリック

image

Bot設定画面で、以下のように設定


  • Webhook送信 「利用する」

  • 自動応答メッセージ 「利用しない」(任意)

  • 友だち追加時あいさつ 「利用しない」(任意)

image

「成功しました」のメッセージがでるので「OK」ボタンをクリック

image

LINE BUSINESS CENTERのアカウントリストに戻って先ほど作成したアカウントの「Messaging API」の見出しの右にある「LINE Developers」ボタンをクリック

image

アカウントの設定画面で以下を実施


  • Webhook URLにHerokuにデプロイしたアプリケーションのURLを設定


    • 今回のsampleでは、HerokuのアプリケーションURLがhttps://salty-badlands-47970.herokuapp.com/だったので、https://salty-badlands-47970.herokuapp.com/callbackと設定する



  • Channel Secretを「SHOW」ボタンを押してメモる

  • Channel Access Tokenを「ISSUE」ボタンを押して発行し、メモる

image

image


Herokuの設定にシークレットとトークンを設定

LINE管理画面で取得したシークレットとトークンをherokuのCLIを利用して環境変数に設定します。

公式SDKの説明のとおりHerokuの管理画面でも出来ます。

以下を実行

❯ heroku config:set LINE_BOT_CHANNEL_TOKEN={メモったChannel Access Token} LINE_BOT_CHANNEL_SECRET={メモったChannel Secret}

Setting LINE_BOT_CHANNEL_TOKEN, LINE_BOT_CHANNEL_SECRET and restarting ⬢ salty-badlands-47970... done, v9
LINE_BOT_CHANNEL_SECRET: {メモったChannel Secret}
LINE_BOT_CHANNEL_TOKEN: {メモったChannel Access Token}

正しく設定されたか不安な場合はheroku configコマンドで確認

上記のheroku config:setコマンドで、Herokuのアプリケーションは自動的に再起動しているはずなので、heroku logsコマンドで起動状態を確認

・・・中略・・・

2016-11-23T12:45:11.027942+00:00 app[web.1]: 2016-11-23 12:45:11.027 INFO 4 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2016-11-23T12:45:11.039393+00:00 app[web.1]: 2016-11-23 12:45:11.039 INFO 4 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2016-11-23T12:45:11.165588+00:00 app[web.1]: 2016-11-23 12:45:11.163 INFO 4 --- [ main] c.l.b.s.b.s.LineMessageHandlerSupport : Registered LINE Messaging API event handler: count = 0
2016-11-23T12:45:11.211816+00:00 app[web.1]: 2016-11-23 12:45:11.211 INFO 4 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 31911 (http)
2016-11-23T12:45:11.218260+00:00 app[web.1]: 2016-11-23 12:45:11.218 INFO 4 --- [ main] com.example.DemoApplication : Started DemoApplication in 8.773 seconds (JVM running for 9.902)
2016-11-23T12:45:11.605169+00:00 heroku[web.1]: State changed from starting to up

起動していました。

起動ログの中にこれがあると完璧

2016-11-23T12:45:09.878281+00:00 app[web.1]: 2016-11-23 12:45:09.878  INFO 4 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/callback],methods=[POST]}" onto public void com.linecorp.bot.spring.boot.support.LineMessageHandlerSupport.callback(java.util.List<com.linecorp.bot.model.event.Event>)


動作確認

自分のLINEアカウントで追加したBOTアカウントを友だちにして(ID検索などを利用)、なにか発言してみてください。

image

自分のuserIdがメッセージで返却されます。

sampleで作成したBOTですが、しばらく残しておくので単純にユーザーIDが知りたい人は何か話しかけてください。



友だち追加