はじめに
LINE Messaging APIをSpringBootで実装するSDKが公式からでていたので試す。
LINE Messaging APIは、httpsでの通信が前提なので、Herokuにアプリケーションをデプロイ(無料)してテストする。
手順
基本的には、公式SDKのgithubのマニュアルのとおり実施しますが、botの内容を発言したユーザーのユーザーIDを返信する処理にしました。
自分のLINEのユーザーIDを知る術がわからなかったので、replyのメッセージから取得したかったというのもあります。
※詳しい人は教えてください。
- SpringBootのプロジェクトを作成
- LINE Messaging APIの公式SDKの
line-bot-spring-boot
をgradleの依存に追加 - sampleを参考にSpringBootの起動クラスにコードを追加
- Herokuにデプロイ
- LINE Messaging APIの
Messaging API Developer Trial
アカウントを追加(もろもろの設定とシークレットとトークンを取得) - Herokuの設定にシークレットとトークンを設定
- 動作確認
詳細
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を始める」のボタンをクリック
アカウントの作成画面がでるので、アカウント名に適当な名前と、業種を適当に選択し、「確認する」ボタンをクリック
確認画面に遷移するので「申し込む」ボタンをクリック
以下の画面に遷移するので、「LINE@MANAGERへ」のボタンをクリック
Bot設定の画面に遷移するので「APIを利用する」ボタンをクリック
「成功しました」のメッセージがでるので「OK」ボタンをクリック
Bot設定画面で、以下のように設定
- Webhook送信 「利用する」
- 自動応答メッセージ 「利用しない」(任意)
- 友だち追加時あいさつ 「利用しない」(任意)
「成功しました」のメッセージがでるので「OK」ボタンをクリック
LINE BUSINESS CENTERのアカウントリストに戻って先ほど作成したアカウントの「Messaging API」の見出しの右にある「LINE Developers」ボタンをクリック
アカウントの設定画面で以下を実施
- Webhook URLにHerokuにデプロイしたアプリケーションのURLを設定
- 今回のsampleでは、HerokuのアプリケーションURLが
https://salty-badlands-47970.herokuapp.com/
だったので、https://salty-badlands-47970.herokuapp.com/callback
と設定する
- 今回のsampleでは、HerokuのアプリケーションURLが
- Channel Secretを「SHOW」ボタンを押してメモる
- Channel Access Tokenを「ISSUE」ボタンを押して発行し、メモる
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検索などを利用)、なにか発言してみてください。
自分のuserIdがメッセージで返却されます。
sampleで作成したBOTですが、しばらく残しておくので単純にユーザーIDが知りたい人は何か話しかけてください。