如今訪問第三方Web資源的情景越來越多,最典型就是使用第三方登錄平台,如QQ或微信等,我們需要訪問騰訊的服務器去驗證登錄者的身份,根據我的經驗,這個過程可能會阻塞好幾秒鍾,可看作是一個“長時間調用”,所以最好要使用異步方式。
maven依賴
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.1</version>
</dependency>
1.線程類 負責處理業務
package com.ruoyi.test; import java.io.UnsupportedEncodingException; /** * Created with IDEA * author:QinWei * Date:2019/4/10 * Time:10:28 */ public class Business extends Thread{ // 回答1+1,很簡單的問題不需要線程 public int add(int num1, int num2) { return num1 + num2; } // 重寫run方法 @Override public void run() { // 回答地球為什么是圓的 askquestion(); super.run(); } // 回調接口的創建,里面要有一個回調方法 //回調接口什么時候用呢?這個思路是最重要的 // public static interface Calls { public void call(String question); } // 回調接口的對象 Calls calls; // 回答地球為什么是圓的 private void askquestion() { System.err.println("開始查找資料!"); try { // 業務請求處理 String succes = Test.main(); // 把答案返回到回調接口的call方法里面 if (calls!=null) {//提問者實例化callPhone對象,相當於提問者已經告訴我,我到時用什么方式回復答案 //這個接口的方法實現是在提問者的類里面 calls.call(succes); } } catch (Exception e) { e.printStackTrace(); } } }
2.請求接口類
package com.ruoyi.test; import com.ruoyi.common.json.JSONObject; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.concurrent.FutureCallback; import org.apache.http.entity.StringEntity; import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClients; import org.apache.http.util.EntityUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.concurrent.CountDownLatch; /** * Created with IDEA * author:QinWei * Date:2019/4/10 * Time:9:15 */ public class Test { public static String main() throws UnsupportedEncodingException { final String[] resData = new String[1]; CloseableHttpAsyncClient client = HttpAsyncClients.createDefault(); client.start(); final CountDownLatch latch = new CountDownLatch(1); final HttpPost post = new HttpPost("http://127.0.0.1:8088/login"); String param1="loginName=6210308024916652&password=123456&captcha=10"; JSONObject param2= new JSONObject(); param2.put("loginName", "6210308024916652"); param2.put("password", "123456"); param2.put("captcha", "4"); //設置請求頭 這里根據個人來定義 post.addHeader("Content-type", "application/json; charset=utf-8"); post.setHeader("Accept", "application/json"); StringEntity stringEntity = new StringEntity(param2.toString()); post.setEntity(stringEntity); //執行 client.execute(post, new FutureCallback<HttpResponse>() { //執行異步操作 請求完成后 @Override public void completed(final HttpResponse response) { latch.countDown(); //響應內容 int a = response.getStatusLine().getStatusCode(); System.out.println("狀態碼:"+a); if (a == 200) { HttpEntity entity = response.getEntity(); try { resData[0] = EntityUtils.toString(entity); } catch (IOException e) { e.printStackTrace(); } System.out.println("成功!"); } else { try { //輸出響內容 System.out.println(response.getStatusLine().getStatusCode() + " " + EntityUtils.toString(response.getEntity(), "UTF-8")); } catch (IOException e) { e.printStackTrace(); } } } //請求失敗處理 @Override public void failed(final Exception ex) { latch.countDown(); } //請求取消后處理 @Override public void cancelled() { latch.countDown(); } }); try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } //關閉 try { client.close(); } catch (IOException ignore) { } return resData[0]; } }
3.測試類
package com.ruoyi.test; /** * Created with IDEA * author:QinWei * Date:2019/4/10 * Time:10:28 */ public class MainClass { /** * java回調方法的使用 * 實際操作時的步驟:(以本實例解釋) * 1.在回答者的類內創建回調的接口 * 2.在回答者的類內創建回調接口的對象, * 3.在提問者類里面實例化接口對象,重寫接口方法 * 2.-3.這個點很重要,回調對象的實例化,要在提問者的類內實例化,然后重寫接口的方法 * 相當於提問者先把一個聯絡方式給回答者,回答者找到答案后,通過固定的聯絡方式,來告訴提問者答案。 * 4.調用開始新線程的start方法 * 5.原來的提問者還可以做自己的事 * */ public static void main(String[] args) { // 小王問小張1+1=?,線程同步 Business xiaoZhang = new Business(); int i = xiaoZhang.add(1, 1);//回答1+1的答案 // 問小張地球為什么是圓的?回調方法的使用 //這相當於先定好一個返答案的方式,再來執行實際操作 // 實例化回調接口的對象 Business.Calls call = new Business.Calls() { @Override public void call(String question) { //回答問題者,回答后,才能輸出答案 System.err.println(question); } }; //把回調對象賦值給回答者的回調對象,回答問題者的回調對象才能回答問題 xiaoZhang.calls = call; System.out.println("吩咐完畢!"); //相關交代完畢之后再執行查詢操作 xiaoZhang.start(); //小王做自己的事! System.out.println("處理自己的業務"); } }
4.請求結果

總結:
1.最好在服務端做一個sleep等待,這樣可以更好的模擬效果
2.開啟一個子線程去執行請求不影響主線程運行,請求完畢后回調給用戶
3.還有很多實現異步回調方式,希望大家評論留言
