微信自動回覆和自動搶紅包實現原理(二):自動回覆
完成AccessibilityService的配置後,好像無從下手。先別急,先列印一些log看看吧。把下面的方法放在onAccessibilityEvent()裡:
private void printEventLog(AccessibilityEvent event) {
Log.i(TAG, "-------------------------------------------------------------");
int eventType = event.getEventType(); //事件型別
Log.i(TAG, "PackageName:" + event.getPackageName() + ""); // 響應事件的包名
Log.i(TAG, "Source Class:" + event.getClassName() + ""); // 事件源的類名
Log.i(TAG, "Description:" + event.getContentDescription()+ ""); // 事件源描述
Log.i(TAG, "Event Type(int):" + eventType + "");
switch (eventType) {
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:// 通知欄事件
Log.i(TAG, "event type:TYPE_NOTIFICATION_STATE_CHANGED");
break;
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED://窗體狀態改變
Log.i(TAG, "event type:TYPE_WINDOW_STATE_CHANGED");
break;
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED://View獲取到焦點
Log.i(TAG, "event type:TYPE_VIEW_ACCESSIBILITY_FOCUSED");
break;
case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
Log.i(TAG, "event type:TYPE_VIEW_ACCESSIBILITY_FOCUSED");
break;
case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
Log.i(TAG, "event type:TYPE_GESTURE_DETECTION_END");
break;
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
Log.i(TAG, "event type:TYPE_WINDOW_CONTENT_CHANGED");
break;
case AccessibilityEvent.TYPE_VIEW_CLICKED:
Log.i(TAG, "event type:TYPE_VIEW_CLICKED");
break;
case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
Log.i(TAG, "event type:TYPE_VIEW_TEXT_CHANGED");
break;
case AccessibilityEvent.TYPE_VIEW_SCROLLED:
Log.i(TAG, "event type:TYPE_VIEW_SCROLLED");
break;
case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
Log.i(TAG, "event type:TYPE_VIEW_TEXT_SELECTION_CHANGED");
break;
default:
Log.i(TAG, "no listen event");
}
for (CharSequence txt : event.getText()) {
Log.i(TAG, "text:" + txt);
}
Log.i(TAG, "-------------------------------------------------------------");
}
向安裝了服務的手機發微信資訊,檢視列印的log:
非鎖屏(在後臺):
-------------------------------------------------------------
packageName:com.tencent.mm
source:null
source class:android.app.Notification
event type(int):64
event type:TYPE_NOTIFICATION_STATE_CHANGED
text:[聯絡人]: 哦
-------------------------------------------------------------
非鎖屏(在前臺主介面):
-------------------------------------------------------------
packageName:com.tencent.mm
source:[email protected]8009b539; boundsInParent: Rect(0, 0 - 38, 38); boundsInScreen: Rect(103, 1181 - 141, 1219); packageName: com.tencent.mm; className: android.widget.TextView; text: 1; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: false; longClickable: false; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null]
source class:android.widget.TextView
event type(int):2048
event type:TYPE_WINDOW_CONTENT_CHANGED
-------------------------------------------------------------
-------------------------------------------------------------
packageName:com.tencent.mm
source:null
source class:android.app.Notification
event type(int):64
event type:TYPE_NOTIFICATION_STATE_CHANGED
text:[聯絡人]: 呵呵
-------------------------------------------------------------
-------------------------------------------------------------
packageName:com.tencent.mm
source:[email protected]80043582; boundsInParent: Rect(0, 0 - 38, 38); boundsInScreen: Rect(96, 153 - 134, 191); packageName: com.tencent.mm; className: android.widget.TextView; text: 1; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: false; longClickable: false; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null]
source class:android.widget.TextView
event type(int):2048
event type:TYPE_WINDOW_CONTENT_CHANGED
-------------------------------------------------------------
非鎖屏(在前臺開啟會話人的介面)(沒Notification)
-------------------------------------------------------------
packageName:com.tencent.mm
source:[email protected]8009cbbf; boundsInParent: Rect(0, 0 - 720, 1038); boundsInScreen: Rect(0, 146 - 720, 1184); packageName: com.tencent.mm; className: android.widget.ListView; text: null; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: true; focused: false; selected: false; clickable: true; longClickable: true; enabled: true; password: false; scrollable: true; actions: [AccessibilityAction: ACTION_FOCUS - null, AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_LONG_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_SCROLL_BACKWARD - null]
source class:android.widget.ListView
event type(int):2048
event type:TYPE_WINDOW_CONTENT_CHANGED
-------------------------------------------------------------
-------------------------------------------------------------
packageName:com.tencent.mm
source:[email protected]801086ca; boundsInParent: Rect(0, 0 - 415, 80); boundsInScreen: Rect(201, 146 - 616, 150); packageName: com.tencent.mm; className: android.widget.TextView; text: 我在敲程式碼,稍後回覆哈~; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: true; longClickable: true; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_LONG_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null]
source class:android.widget.TextView
event type(int):2048
event type:TYPE_WINDOW_CONTENT_CHANGED
-------------------------------------------------------------
-------------------------------------------------------------
packageName:com.tencent.mm
source:[email protected]8009cbbf; boundsInParent: Rect(0, 0 - 720, 1038); boundsInScreen: Rect(0, 146 - 720, 1184); packageName: com.tencent.mm; className: android.widget.ListView; text: null; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: true; focused: false; selected: false; clickable: true; longClickable: true; enabled: true; password: false; scrollable: true; actions: [AccessibilityAction: ACTION_FOCUS - null, AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_LONG_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_SCROLL_BACKWARD - null]
source class:android.widget.ListView
event type(int):4096
event type:TYPE_VIEW_SCROLLED
-------------------------------------------------------------
非鎖屏(在前臺開啟非會話人的介面):
-------------------------------------------------------------
packageName:com.tencent.mm
source:[email protected]800ce011; boundsInParent: Rect(0, 0 - 95, 80); boundsInScreen: Rect(104, 851 - 199, 931); packageName: com.tencent.mm; className: android.widget.TextView; text: [白眼]; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: true; longClickable: true; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_LONG_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null]
source class:android.widget.TextView
event type(int):2048
event type:TYPE_WINDOW_CONTENT_CHANGED
-------------------------------------------------------------
-------------------------------------------------------------
packageName:com.tencent.mm
source:null
source class:android.app.Notification
event type(int):64
event type:TYPE_NOTIFICATION_STATE_CHANGED
text:[聯絡人]: 呵呵
-------------------------------------------------------------
-------------------------------------------------------------
packageName:com.tencent.mm
source:[email protected]8012f5f0; boundsInParent: Rect(0, 0 - 371, 60); boundsInScreen: Rect(174, 591 - 545, 651); packageName: com.tencent.mm; className: android.widget.TextView; text: "?彣????" 撤回了一條訊息; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: true; longClickable: false; enabled: true; password: false; scrollable: false; actions: [AccessibilityAction: ACTION_SELECT - null, AccessibilityAction: ACTION_CLEAR_SELECTION - null, AccessibilityAction: ACTION_CLICK - null, AccessibilityAction: ACTION_ACCESSIBILITY_FOCUS - null, AccessibilityAction: ACTION_NEXT_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY - null, AccessibilityAction: ACTION_SET_SELECTION - null]
source class:android.widget.TextView
event type(int):2048
event type:TYPE_WINDOW_CONTENT_CHANGED
-------------------------------------------------------------
從列印的log和我們平時使用微信應該就知道的了,除了在打開了會話人的聊天介面,否則都會有Notification的,可以以此作為切入點,那麼接下來我們的工作就簡單了。步驟如下:
1. 監聽TYPE_NOTIFICATION_STATE_CHANGED事件
2. 根據Notification開啟會話人聊天介面
3. 搜尋輸入框控制元件
4. 在輸入框輸入回覆文字
5. 點擊發送按鈕
6. 返回微信主介面
思路很清晰了,難點是如何找到相應的控制元件。放心,Android也為我們提供了一個類來幫助我們——AccessibilityNodeInfo ,其包含一些控制元件的資訊,可用其找到相應的控制元件,並做出相應的操作。常用方法:
- CharSequence getClassName () // 獲取控制元件類名,如按鈕會返回android.widget.Button
- CharSequence getText () // 獲取控制元件的文字,如微信的傳送按鈕會返回“傳送”
- String getViewIdResourceName () // 獲取控制元件的id
程式碼註釋很詳細了,就不一一解釋。原始碼後面有貼。
/**
* 自動回覆服務
*/
public class AutoReplyService extends AccessibilityService{
private static final String TAG = AutoReplyService.class.getSimpleName();
private Handler handler = new Handler();
private boolean hasNotify = false;
/**
* 必須重寫的方法,響應各種事件。
*/
@Override
public void onAccessibilityEvent(final AccessibilityEvent event) {
int eventType = event.getEventType(); // 事件型別
switch (eventType) {
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: // 通知欄事件
Log.i(TAG, "TYPE_NOTIFICATION_STATE_CHANGED");
if(PhoneController.isLockScreen(this)) { // 鎖屏
PhoneController.wakeAndUnlockScreen(this); // 喚醒點亮螢幕
}
openAppByNotification(event);
hasNotify = true;
break;
default:
Log.i(TAG, "DEFAULT");
if (hasNotify) { // 如果有通知
try {
Thread.sleep(1000); // 停1秒, 否則在微信主介面沒進入聊天介面就執行了fillInputBar
} catch (InterruptedException e) {
e.printStackTrace();
}
if (fillInputBar("我在敲程式碼,稍後回覆哈~")) { // 找到輸入框,即EditText
findAndPerformAction(UI.BUTTON, "傳送"); // 點擊發送
handler.postDelayed(new Runnable() { // 返回主介面,這裡延遲執行,為了有更好的互動
@Override
public void run() {
performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK); // 返回
}
}, 1500);
}
hasNotify = false;
}
break;
}
}
@Override
public void onInterrupt() {
}
/**
* 查詢UI控制元件並點選
* @param widget 控制元件完整名稱, 如android.widget.Button, android.widget.TextView
* @param text 控制元件文字
*/
private void findAndPerformAction(String widget, String text) {
// 取得當前啟用窗體的根節點
if (getRootInActiveWindow() == null) {
return;
}
// 通過文字找到當前的節點
List<AccessibilityNodeInfo> nodes = getRootInActiveWindow().findAccessibilityNodeInfosByText(text);
if(nodes != null) {
for (AccessibilityNodeInfo node : nodes) {
if (node.getClassName().equals(widget) && node.isEnabled()) {
node.performAction(AccessibilityNodeInfo.ACTION_CLICK); // 執行點選
break;
}
}
}
}
/**
* 開啟微信
* @param event 事件
*/
private void openAppByNotification(AccessibilityEvent event) {
if (event.getParcelableData() != null && event.getParcelableData() instanceof Notification) {
Notification notification = (Notification) event.getParcelableData();
try {
PendingIntent pendingIntent = notification.contentIntent;
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
}
/**
* 填充輸入框
*/
private boolean fillInputBar(String reply) {
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
if (rootNode != null) {
return findInputBar(rootNode, reply);
}
return false;
}
/**
* 查詢EditText控制元件
* @param rootNode 根結點
* @param reply 回覆內容
* @return 找到返回true, 否則返回false
*/
private boolean findInputBar(AccessibilityNodeInfo rootNode, String reply) {
int count = rootNode.getChildCount();
for (int i = 0; i < count; i++) {
AccessibilityNodeInfo node = rootNode.getChild(i);
if (UI.EDITTEXT.equals(node.getClassName())) { // 找到輸入框並輸入文字
setText(node, reply);
return true;
}
if (findInputBar(node, reply)) { // 遞迴查詢
return true;
}
}
return false;
}
/**
* 設定文字
*/
private void setText(AccessibilityNodeInfo node, String reply) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Bundle args = new Bundle();
args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
reply);
node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args);
} else {
ClipData data = ClipData.newPlainText("reply", reply);
ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboardManager.setPrimaryClip(data);
node.performAction(AccessibilityNodeInfo.ACTION_FOCUS); // 獲取焦點
node.performAction(AccessibilityNodeInfo.ACTION_PASTE); // 執行貼上
}
}
}
這裡我沒有處理打開了會話人聊天介面的情況,我覺得你都打開了會話人的聊天介面,就證明你想與他聊天,也就不需要自動回覆了。當然,如果你遍要(不帶你這樣敷衍朋友的),只要加點簡單邏輯就可以實現了~到這裡微信自動回覆功能就完成了,怎樣,是不是很簡單!感興趣的朋友可以繼續看我下一篇文章:
微信自動回覆和自動搶紅包實現原理(三):自動搶紅包
相關推薦
微信自動回覆和自動搶紅包實現原理(二):自動回覆
完成AccessibilityService的配置後,好像無從下手。先別急,先列印一些log看看吧。把下面的方法放在onAccessibilityEvent()裡: private void printEventLog(Accessibilit
微信自動回覆和自動搶紅包實現原理(三):自動搶紅包
經過前兩篇文章的閱讀,我相信大家應該對AccessibilityService有一定的瞭解了,是不是已經按捺不住,想自己動手試試?先別急,可以再看完我這篇文章還不遲,相信你另有收穫的。接下來我們來探索一下自動搶紅包的實現原理。 看了我第二篇微信自動回覆
從微信小程式開發者工具原始碼看實現原理(二)- - 小程式技術實現
wxml與wxss的轉換 1、wxml使用wcc轉換 2、wxss使用wcsc轉換 開發者工具主入口 檢視層頁面的實現 檢視層頁面實現技術細節 檢視層快速開啟原理 檢視層新開啟頁面流程 業務邏輯層頁面的實現 wxml與wxss的轉換 開啟小程式開發者工具,在除錯控制檯輸入openVendor就會開
從微信小程式開發者工具原始碼看實現原理(一)- - 小程式架構設計
使用微信小程式開發已經很長時間了,對小程式開發已經相當熟練了;但是作為一名對技術有追求的前端開發,僅僅熟練掌握小程式的開發感覺還是不夠的,我們應該更進一步的去理解其背後實現的原理以及對應的考量,這可能會解釋我們在開發過程中遇到的一些疑惑,比如為啥小程式不能操作dom、小程式是web技術渲染還是native技術
從微信小程式開發者工具原始碼看實現原理(四)- - 自適應佈局
從前面從微信小程式開發者工具原始碼看實現原理(一)- - 小程式架構設計可以知道,小程式大部分是通過web技術進行渲染的,也就是最終通過瀏覽器的dom tree + cssom來生成渲染樹;既然最終是通過css來繪製ui佈局,我們知道小程式提供的自適應css單位rpx在瀏覽器環境根本不被識別,所以小程式最終還
微信專案開發與本地除錯、移動除錯(二)
簡單講一下利用微信官方提供的工具--微信web開發者工具,進行微信工程的本地除錯和測試、生產環境的除錯。 本地除錯, 利用自己申請的訂閱號的公眾平臺測試賬號測試。 1、按照上篇文章中介紹的,設定網
thinkphp5.1框架解析(二):自動載入
繼 生命週期的第二篇,大家儘可放心,不會隨便鴿文章的 第一篇中,我們提到了入口指令碼,也說了,裡面註冊了自動載入的功能 本文預設你有自動載入和名稱空間的基礎。如果沒有請 看此篇文章 php 類的自動載入與名稱空間 自動載入機制 php 的自動
微信公眾平臺萬能程式碼詳解-php語言(二)
1.基礎知識在上一篇地址有講解和圖片,內容大致包括微信開發者模式後臺配置、微信公眾開發者文件程式碼詳解。 2.本篇將粘貼出包括所有型別在內的訊息處理辦法,在開發者模式下用程式碼完成所有編輯模式的基礎內容。 3.本篇程式碼是最基礎的微信公眾平臺功能,大家要掌握如何套用。 =
微信公眾號開發中遇到的問題——支付(二)
第一次開發微信公眾號,也是第一次接觸微信公眾號的支付,我使用的是jssdk,用h5頁面呼叫的支付,後臺使用的是java。首先宣告,我不是一個憤世嫉俗的人,也不喜歡吐槽,我認為別人提供介面就已經很不錯了,幹嘛要吐槽呢?但是,這一次,我不得不說,微信公眾號支付的文件真是渣!!!
Python和C|C++的混編(二):利用Cython進行混編
cde uil 有時 當前 class def 將在 python 混編 還能夠使用Cython來實現混編 1 下載Cython。用python setup.py install進行安裝 2 一個實例 ① 創建helloworld文件夾創建hellowor
用Java實現JVM(二):支援介面、類和物件
1. 概述我的 JVM 已經能夠執行HelloWorld了,並且有了基本的 JVM 骨架,包括執行時資料結構的定義(棧、棧幀、運算元棧等),執行時的邏輯控制等。但它還沒有類和物件的概念,比如無法執行下面這更復雜的HelloWorld:public interface SpeakerInterface {
Java語法糖(2):自動裝箱和自動拆箱
eth 空指針 lang 指針 反編譯 class path load pointer 自動拆箱和自動裝箱 Java為每種基本數據類型都提供了對應的包裝器類型。舉個例子: public class TestMain{public static void main(Strin
Spring Cloud Eureka原理分析(二):續租、下線、自我保護機制和自動清理(服務端)
續租、下線等操作比較直觀,實際上也不復雜。讓我們自己想想它們大概會在服務端有什麼操作。 renew: 更新Lease的lastUpdateTimestamp, 更新一下InstanceInfo的最新狀態。然後呼叫其他同伴節點的renew介面。 cancel:把lease從registry中移除,設
Android自動接聽和結束通話電話實現原理
轉自:http://bbs.51cto.com/thread-1078059-1.html 一 前言 這兩天要研究類似白名單黑名單以及手勢自動接聽的一些功能,所以呢,自然而然的涉及到怎麼自動接聽/結束通話電話的功能了。 對於自動接聽這一塊,android4.1
微信公眾號開發整理(二)--圖文訊息回覆
1.由於個人公眾號許多介面許可權用不了,這裡方便測試,我們採用測試賬號進行開發:2.找到回覆圖文訊息相關API文件首先查看回復圖文訊息文字格式如下:3.上一篇建立了一個公用的實體類,這次建立圖文訊息的回覆,我們只需要繼承公用的父類,具體實體類如下:public class N
TF-IDF與余弦相似性的應用(三):自動摘要
下一步 dip target 似的 abs tps .net ebo ace 轉:http://www.ruanyifeng.com/blog/2013/03/automatic_summarization.html 有時候,很簡單的數學方法,就可以完成很復雜的任務。 這個
微信網頁分享標題圖片自定義設置(最新)
內容 outline 朋友圈 exe ech pem read 解決方法 highlight 1 前言 剛好有微信網頁分享標題圖片自定義設置這個需求,然後查找文檔,發現有兩種方案[1],但是第一種方案已經失效了,只能走第二種方案,然後根據實戰配置好了,本文會寫上配置中遇到的
rest-assured介面自動化(二):往execl中增加用例,自動執行所有介面
利用空閒之餘,寫了第一個介面自動化測試demo, 通過讀取execl中的介面測試用例,介面自動執行。(這裡跟很多網上的介面自動化有點不同的是:無需再寫程式碼,只需要從execl中增加用例,就可執行)。 這是execl的模板: 這個模板可以很好的管理專案的各個模組,看起來也是簡潔,也是頗為喜
Zabbix監控系統(二):Zabbix管理之自動發現服務
1. 建立自動發現 配置->自動發現->建立發現規則 設定名稱 配置IP範圍 設定延遲時間 設定IP地址為唯一性準則 啟用發現規則 2. 建立動作 配置->動作->建立動作 2.1 設定執
Spring Boot + Spring Cloud 構建微服務系統(二):服務消費和負載(Ribbon)
使用RestTemplate呼叫服務 在上一篇教程中,我們是這樣呼叫服務的,先通過 LoadBalancerClient 選取出對應的服務,然後使用 RestTemplate 進行遠端呼叫。 LoadBalancerClient 就是負載均衡器,預設使用的是 Ribbon 的實現 RibbonLoadBa