Line Robot ( 三 ) - 實作echo Robot

言:    此功能如標題所描述,當使用者對Line Robot傳送什麼訊息,Line Robot就回應什麼訊息至使用者。

編譯環境(工具):
JDK1.8、eclipse

開始製作:
    前幾篇有提到,編寫Line Robot如同撰寫Web API,而在Java近幾年比較流行使用Spring boot開發,故作者以Spring boot框架去製作,而在Spring boot官網中有提供Spring Initializr製作Spring boot的開發包,故我們先點選我們所需要的套件後並下載。


將專案導入至eclipse


接著先撰寫測試的API街口判斷Spring boot是否正常運作(萬年的 Hello java出場)
@RequestMapping("/robot")
@RestController
public class RobotController {
 @Value("${line.user.secret}")
 private String LINE_SECRET;
 @Autowired
 private HttpServletRequest httpServletRequest;
 
 @GetMapping("/test")
 public ResponseEntity test(){
  return new ResponseEntity("Hello J A V A", HttpStatus.OK);
 }
}
    完工後運行並在瀏覽器輸入  http://localhost:8080/robot/test ,網頁是否出現Hello Java等字樣,如果有的話證明了Spring boot功能正常,接著開始進入主題 - Line echo robot。
    首先在第二章節有提到所有Line的訊息皆是由Line伺服器傳送至Line robot中,而其間的協定走的是Post Method,且還要處理第二章節提到的Line伺服器驗證故作者的程式如下:
public boolean checkFromLine(String requestBody, String X_Line_Signature) {
 SecretKeySpec key = new SecretKeySpec(LINE_SECRET.getBytes(), "HmacSHA256");
 Mac mac;
 try {
  mac = Mac.getInstance("HmacSHA256");
  mac.init(key);
  byte[] source = requestBody.getBytes("UTF-8");
  String signature = Base64.encodeBase64String(mac.doFinal(source));
  if(signature.equals(X_Line_Signature)) {
   return true;
  }
 } catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 }
 
 return false;
}

接著定義接收Line platform訊息接口,但在那之前須先了解Line Platform回傳的訊息封裝格式有助於解析並做應用,在前一章有提到,其格式內容主要是用JSON進行封裝,JSON內會含兩項,destination及events,其中events所代表的是Line接收到使用者的各個訊息回應,而本章節會使用到的是Message event,其格式內容如下圖所示
@PostMapping("/messaging")
public ResponseEntity messagingAPI(@RequestHeader("X-Line-Signature") String X_Line_Signature, @RequestBody String requestBody) throws UnsupportedEncodingException, IOException{
 if(checkFromLine(requestBody, X_Line_Signature)) {
  System.out.println("驗證通過");
  JSONObject obje ct = new JSONO bject(requestBody);
  for(int i=0; i<object.getJSONArray("events").length(); i++) {
   if(object.getJSONArray("events").getJSONObject(i).getString("type").equals("message")) {
    messageHandler.doAction(object.getJSONArray("events").getJSONObject(i));
   }
  }
  return new ResponseEntity<String>("OK", HttpStatus.OK);
 }
 System.out.println("驗證不通過");
 return new ResponseEntity<String>("Not line platform", HttpStatus.BAD_GATEWAY);
}
另外為了維護方便,作者另外撰寫了解析events訊息的class檔(MessageHandler)專門處理message event
@Component
public class MessageHandler {
 private OkHttpClient client = new OkHttpClient();
 @Value("${line.user.channel.token}")
 private String LINE_TOKEN;
 public void doAction(JSONObject event) {
  switch (event.getJSONObject("message").getString("type")) {
   case "text":
    text(event.getString("replyToken"), event.getJSONObject("message").getString("text"));
    break;
   case "sticker":
    sticker(event.getString("replyToken"), event.getJSONObject("message").getString("packageId"), event.getJSONObject("message").getString("stickerId"));
    break;
  }
 }
 
 private void text(String replyToken, String text) {
  JSONObject body = new JSONObject();
  JSONArray messages = new JSONArray();
  JSONObject message = new JSONObject();
  message.put("type", "text");
  message.put("text", text);
  messages.put(message);
  body.put("replyToken", replyToken);
  body.put("messages", messages);
  sendLinePlatform(body);
 }
 private void sticker(String replyToken, String packageId, String stickerId) {
  JSONObject body = new JSONObject();
  JSONArray messages = new JSONArray();
  JSONObject message = new JSONObject();
  message.put("type", "sticker");
  message.put("packageId", packageId);
  message.put("stickerId", stickerId);
  messages.put(message);
  body.put("replyToken", replyToken);
  body.put("messages", messages);
  sendLinePlatform(body);
 }
 
 public void sendLinePlatform(JSONObject json) {
  Request request = new Request.Builder()
    .url("https://api.line.me/v2/bot/message/reply")
    .header("Authorization", "Bearer {"+LINE_TOKEN+"}")
    .post(RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json.toString()))
    .build();
  client.newCall(request).enqueue(new Callback() {
   
   @Override
   public void onResponse(Call call, Response response) throws IOException {
    System.out.println(response.body());
   }
   
   @Override
   public void onFailure(Call call, IOException e) {
    System.err.println(e);
   }
  });
 }
}
    其中可以看到兩個重點,一是Line Robot要回應訊息需透過Line官方提供的Reply-API("https://api.line.me/v2/bot/message/reply"),二是傳遞的格式,兩者會在之後的章節再詳細介紹,程式完成後就要將Line Robot正式上線。
    上線的方法要先回到第一章節中Line機器人資訊,在Bassic Settings中的Channel secret為驗證Request是否來的Line Platform的LINE_SECRET,而在Messaging API中則要做一些基本資訊


    在Webhook URL中須設定Line Robot的IP位置,其中Line官方的規範中,Line Robot須是走Https協定且不能是明碼,故本文章是使用Heroku免費的雲端平台進行測試,以及須開啟Use webhook選項
    設定完成之後就可以實際上線測試咯~



留言

這個網誌中的熱門文章

Python-相關係數矩陣實作(python-correlation matrix )

ASP.NET-後端將值傳給javascript

ASP.NET-FileUpload上傳後自動觸發button click(FileUpload upload auto trigger button click)