在Line中,使用者與聊天機器人對話時,輸入的訊息(包括文字、圖片、聲音及影片等)會傳到我們建立的網頁伺服器中,並由網頁伺服器中,webhook設定網址的方法(在我的範例是calback方法)接收此訊息,接收到訊息後,您就可針對接收的訊息進行處理,並回應給使用者。
1. 了解Line傳送給網頁伺服器的資料格式 (說明影片)
聊天機器人與網頁伺服器間傳遞的訊息為json格式的字串,您可以在Line中對聊天機器人輸入文字、圖片、貼圖等訊息,並由Eclipse的console中,查看callback方法會接收到怎樣的json格式的字串。如下在Line中輸入 Hello!
在Eclipse的console中會顯示如下json格式的字串
{
"events": [
{
"type": "message",
"replyToken": "18dd8eaf30c8404da1de06002cde05b9",
"source": {
"userId": "U470a93ec2caaa5ab9a42f528884ff27b",
"type": "user"
},
"timestamp": 1497875299568,
"message": {
"type": "text",
"id": "6263732340746",
"text": "Hello!"
}
}
]
}
練習:您可以在Line中輸入不同的訊息,如圖片、錄音、貼圖、位置等,並Eclipse的console中觀看獲得的json格式的字串。
您也可到Line Messaging API Reference查看完整的json資料格式,如下:
2. webhook event object的說明
webhook接收的json格式字串是一個webhook event object,此物件(events)包含1~多個event物件。
每個event物件包含以下幾個屬性:
3. 將json格式的字串轉換為物件 (說明影片)
取得此json格式字串的某些值,若用字串處理會非常麻煩(如replytoken的值),我們通常會將此字串轉換為物件再進行後續處理,而目前已有很多API能把json格式的字串轉換為物件,如java的jackson API、C#的Newtonsoft.Json。
要將json格式的字串轉換為物件,需先製作json格式的字串相對應的物件,在此須製作Source、Message、Event、EventWrapper物件,完整程式碼如下:
public class Source {
private String type;
private String userId;
private String groupId;
private String roomId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getRoomId() {
return roomId;
}
public void setRoomId(String roomId) {
this.roomId = roomId;
}
}
public class Message {
private String id;
private String type;
private String text;
private String filename;
private String filesize;
private String title;
private String address;
private String latitude;
private String longitude;
private String packageId;
private String stickerId;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public String getPackageId() {
return packageId;
}
public void setPackageId(String packageId) {
this.packageId = packageId;
}
public String getStickerId() {
return stickerId;
}
public void setStickerId(String stickerId) {
this.stickerId = stickerId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getFilesize() {
return filesize;
}
public void setFilesize(String filesize) {
this.filesize = filesize;
}
}
public class Event {
private String replyToken;
private String type;
private Source source;
private String timestamp;
private Message message;
public String getReplyToken() {
return replyToken;
}
public void setReplyToken(String replyToken) {
this.replyToken = replyToken;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Source getSource() {
return source;
}
public void setSource(Source source) {
this.source = source;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
}
public class EventWrapper {
private List<Event> events;
public List<Event> getEvents() {
return events;
}
public void setEvents(List<Event> events) {
this.events = events;
}
}
在設計這些物件後,callback方法的參數要修改,因spring mvc的controller會自動將傳進來的json格式字串自動轉換為物件,所以只需將程式修改如下:
@RestController
public class LineBotRSController {
@RequestMapping(value="/callback")
public void callback(@RequestBody EventWrapper events) {
for(Event event:events.getEvents()){ //用一個迴圈,一個個取得event物件
System.out.println(event.getReplyToken()); //透過Event物件的getReplyToken()方法取得replyToken,並在console顯示此replyToken
}
}
}
4. 回應訊息(reply message)(說明影片)
回應訊息可參考Line Messaging API的Reply mesage說明
HTTP request Request headers Request body |
如上說明,回應訊息是透過post方法,將回應訊息放在request body,傳送到https://api.line.me/v2/bot/message/reply網址,傳送時Request headers需有Content-Type及Authorization
有幾點須注意:
a. Channel Access Token可在設定webhook的網頁獲得,
b. 回傳的訊息須放在request body,是一個json格式的字串,包含replyToken及messages兩個屬性
c. replyToken會在30秒後失效,所以您需在接收到訊息時立刻回應
d. 每次回傳的訊息最多5個
因此要回傳訊息我們增加了一個sendResponseMessages方法及修改callback方法,程式碼如下,此程式會將使用者傳來的文字訊息在其前加上echo字串後,回應給使用者。
@RestController
public class LineBotRSController {
private String accessToken="k210L48XnXW2xONK9WsQjl+fcEUmXswIyLQ1fpIZebkupa0ET+IVphTM5dknlWTW65aCf9WkR+vx/nFLa+ZW1b5FTy22xhReEOZpf6TYF9nk9I0wU/gT6jlCwdrvG9ySugBC1LSo4uWVaY7C9ig6HQdB04t89/1O/w1cDnyilFU=";
@RequestMapping(value="/callback")
public void callback(@RequestBody EventWrapper events) {
for(Event event:events.getEvents()){
switch(event.getType()){
case "message": //當event為message時進入此case執行,其他event(如follow、unfollow、leave等)的case在此省略,您可自己增加
System.out.print("This is a message event!");
switch(event.getMessage().getType()){
case "text": //當message type為text時,進入此case執行,目前子是將使用者傳來的文字訊息在其前加上echo字串後,回傳給使用者
sendResponseMessages(event.getReplyToken(), event.getMessage().getText());
System.out.println("This is a text message. It's replytoken is "+event.getReplyToken());
break;
case "image"://當message type為image時,進入此case執行,
System.out.println("This is a image message. It's replytoken is "+event.getReplyToken());
break;
case "audio"://當message type為audio時,進入此case執行,
System.out.println("This is a audio message. It's replytoken is "+event.getReplyToken());
break;
case "video"://當message type為video時,進入此case執行,
System.out.println("This is a video message. It's replytoken is "+event.getReplyToken());
break;
case "file"://當message type為file時,進入此case執行,
System.out.println("This is a file message. It's replytoken is "+event.getReplyToken());
break;
case "sticker"://當message type為sticker時,進入此case執行,
System.out.println("This is a sticker message. It's replytoken is "+event.getReplyToken());
break;
case "location"://當message type為location時,進入此case執行,
System.out.println("This is a location message. It's replytoken is "+event.getReplyToken());
break;
}
break;
}
}
}
private void sendResponseMessages(String replyToken, String message) {
try {
message = "{\"replyToken\":\""+replyToken+"\",\"messages\":[{\"type\":\"text\",\"text\":\"echo "+message+"\"}]}"; //回傳的json格式訊息
URL myurl = new URL("https://api.line.me/v2/bot/message/reply"); //回傳的網址
HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection(); //使用HttpsURLConnection建立https連線
con.setRequestMethod("POST");//設定post方法
con.setRequestProperty("Content-Type", "application/json; charset=utf-8"); //設定Content-Type為json
con.setRequestProperty("Authorization", "Bearer "+this.accessToken); //設定Authorization
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream( con.getOutputStream() ); //開啟HttpsURLConnection的連線
output.write( message.getBytes(Charset.forName("utf-8")) ); //回傳訊息編碼為utf-8
output.close();
System.out.println("Resp Code:"+con .getResponseCode()+"; Resp Message:"+con .getResponseMessage()); //顯示回傳的結果,若code為200代表回傳成功
} catch (MalformedURLException e) {
System.out.println("Message: "+e.getMessage());
e.printStackTrace();
} catch (IOException e) {
System.out.println("Message: "+e.getMessage());
e.printStackTrace();
}
}
}