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的開發包,故我們先點選我們所需要的套件後並下載。
編譯環境(工具):
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選項
設定完成之後就可以實際上線測試咯~
留言
張貼留言