094實戰 關於js SDK的程序,java SDK的程序

一:JS SDKjavascript

1.修改配置workspacehtml

  

 

2.導入java

  

 

3.Demo.html linux

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 2 <html>
 3 <head>
 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 5 <title>測試頁面1</title>
 6 <!-- 第一種集成方式 -->
 7 <script type="text/javascript" src="./js/analytics.js"></script>
 8 </head>
 9 <body>
10     測試頁面1<br/>
11     跳轉到:
12     <a href="demo.html">demo</a>
13     <a href="demo2.html">demo2</a>
14     <a href="demo3.html">demo3</a>
15     <a href="demo4.html">demo4</a>
16 </body>
17 </html>

 

4.效果nginx

  

 

5.產生新的日誌web

  tail -f access.log瀏覽器

  

 

二:重點服務器

1.關於js的產生cookie

  參考程序analytics.js的JS SDKsession

  1 (function() {
  2     var CookieUtil = {
  3         // get the cookie of the key is name
  4         get : function(name) {
  5             var cookieName = encodeURIComponent(name) + "=", cookieStart = document.cookie
  6                     .indexOf(cookieName), cookieValue = null;
  7             if (cookieStart > -1) {
  8                 var cookieEnd = document.cookie.indexOf(";", cookieStart);
  9                 if (cookieEnd == -1) {
 10                     cookieEnd = document.cookie.length;
 11                 }
 12                 cookieValue = decodeURIComponent(document.cookie.substring(
 13                         cookieStart + cookieName.length, cookieEnd));
 14             }
 15             return cookieValue;
 16         },
 17         // set the name/value pair to browser cookie
 18         set : function(name, value, expires, path, domain, secure) {
 19             var cookieText = encodeURIComponent(name) + "="
 20                     + encodeURIComponent(value);
 21 
 22             if (expires) {
 23                 // set the expires time
 24                 var expiresTime = new Date();
 25                 expiresTime.setTime(expires);
 26                 cookieText += ";expires=" + expiresTime.toGMTString();
 27             }
 28 
 29             if (path) {
 30                 cookieText += ";path=" + path;
 31             }
 32 
 33             if (domain) {
 34                 cookieText += ";domain=" + domain;
 35             }
 36 
 37             if (secure) {
 38                 cookieText += ";secure";
 39             }
 40 
 41             document.cookie = cookieText;
 42         },
 43         setExt : function(name, value) {
 44             this.set(name, value, new Date().getTime() + 315360000000, "/");
 45         }
 46     };
 47 
 48     // 主體,其實就是tracker js
 49     var tracker = {
 50         // config
 51         clientConfig : {
 52             // TODO 這裏的url須要傳入具體的地址
 53             serverUrl : "http://linux-hadoop3.ibeifeng.com/BEIfeng.gif",
 54             sessionTimeout : 360, // 360s -> 6min  指定會話的過時時間,指的是操做停留最多的時間
 55             maxWaitTime : 3600, // 3600s -> 60min -> 1h 指定的是單頁面的最多停留時間,當前這個參數無效
 56             ver : "1"
 57         },
 58 
 59         cookieExpiresTime : 315360000000, // cookie過時時間,10年
 60 
 61         columns : {
 62             // 發送到服務器的列名稱
 63             eventName : "en",
 64             version : "ver",
 65             platform : "pl",
 66             sdk : "sdk",
 67             uuid : "u_ud",
 68             memberId : "u_mid",
 69             sessionId : "u_sd",
 70             clientTime : "c_time",
 71             language : "l",
 72             userAgent : "b_iev",
 73             resolution : "b_rst",
 74             currentUrl : "p_url",
 75             referrerUrl : "p_ref",
 76             title : "tt",
 77             orderId : "oid",
 78             orderName : "on",
 79             currencyAmount : "cua",
 80             currencyType : "cut",
 81             paymentType : "pt",
 82             category : "ca",
 83             action : "ac",
 84             kv : "kv_",
 85             duration : "du"
 86         },
 87 
 88         keys : {
 89             pageView : "e_pv",
 90             chargeRequestEvent : "e_crt",
 91             launch : "e_l",
 92             eventDurationEvent : "e_e",
 93             sid : "bftrack_sid",
 94             uuid : "bftrack_uuid",
 95             mid : "bftrack_mid",
 96             preVisitTime : "bftrack_previsit",
 97 
 98         },
 99 
100         /**
101          * 獲取會話id
102          */
103         getSid : function() {
104             return CookieUtil.get(this.keys.sid);
105         },
106 
107         /**
108          * 保存會話id到cookie
109          */
110         setSid : function(sid) {
111             if (sid) {
112                 CookieUtil.setExt(this.keys.sid, sid);
113             }
114         },
115 
116         /**
117          * 獲取uuid,從cookie中
118          */
119         getUuid : function() {
120             return CookieUtil.get(this.keys.uuid);
121         },
122 
123         /**
124          * 保存uuid到cookie
125          */
126         setUuid : function(uuid) {
127             if (uuid) {
128                 CookieUtil.setExt(this.keys.uuid, uuid);
129             }
130         },
131 
132         /**
133          * 獲取memberID
134          */
135         getMemberId : function() {
136             return CookieUtil.get(this.keys.mid);
137         },
138 
139         /**
140          * 設置mid
141          */
142         setMemberId : function(mid) {
143             if (mid) {
144                 CookieUtil.setExt(this.keys.mid, mid);
145             }
146         },
147 
148         // 入口方法
149         startSession : function() {
150             // 加載js就觸發的方法
151             if (this.getSid()) {
152                 // 會話id存在,表示uuid也存在
153                 if (this.isSessionTimeout()) {
154                     // 會話過時,產生新的會話
155                     this.createNewSession();
156                 } else {
157                     // 會話沒有過時,更新最近訪問時間
158                     this.updatePreVisitTime(new Date().getTime());
159                 }
160             } else {
161                 // 會話id不存在,表示uuid也不存在
162                 this.createNewSession();
163             }
164             this.onPageView();
165         },
166 
167         onLaunch : function() {
168             // 觸發launch事件
169             var launch = {};
170             launch[this.columns.eventName] = this.keys.launch; // 設置事件名稱
171             this.setCommonColumns(launch); // 設置公用columns
172             this.sendDataToServer(this.parseParam(launch)); // 最終發送編碼後的數據
173         },
174 
175         onPageView : function() {
176             // 觸發page view事件
177             if (this.preCallApi()) {
178                 var time = new Date().getTime();
179                 var pageviewEvent = {};
180                 pageviewEvent[this.columns.eventName] = this.keys.pageView;
181                 pageviewEvent[this.columns.currentUrl] = window.location.href; // 設置當前url
182                 pageviewEvent[this.columns.referrerUrl] = document.referrer; // 設置前一個頁面的url
183                 pageviewEvent[this.columns.title] = document.title; // 設置title
184                 this.setCommonColumns(pageviewEvent); // 設置公用columns
185                 this.sendDataToServer(this.parseParam(pageviewEvent)); // 最終發送編碼後的數據
186                 this.updatePreVisitTime(time); // 更新最近訪問時間
187             }
188         },
189 
190         onChargeRequest : function(orderId, name, currencyAmount, currencyType,
191                 paymentType) {
192             // 觸發訂單產生事件
193             if (this.preCallApi()) {
194                 if (!orderId || !currencyType || !paymentType) {
195                     this.log("訂單id、貨幣類型以及支付方式不能爲空");
196                     return;
197                 }
198 
199                 if (typeof (currencyAmount) == "number") {
200                     // 金額必須是數字
201                     var time = new Date().getTime();
202                     var chargeRequestEvent = {};
203                     chargeRequestEvent[this.columns.eventName] = this.keys.chargeRequestEvent;
204                     chargeRequestEvent[this.columns.orderId] = orderId;
205                     chargeRequestEvent[this.columns.orderName] = name;
206                     chargeRequestEvent[this.columns.currencyAmount] = currencyAmount;
207                     chargeRequestEvent[this.columns.currencyType] = currencyType;
208                     chargeRequestEvent[this.columns.paymentType] = paymentType;
209                     this.setCommonColumns(chargeRequestEvent); // 設置公用columns
210                     this.sendDataToServer(this.parseParam(chargeRequestEvent)); // 最終發送編碼後的數據ss
211                     this.updatePreVisitTime(time);
212                 } else {
213                     this.log("訂單金額必須是數字");
214                     return;
215                 }
216             }
217         },
218 
219         onEventDuration : function(category, action, map, duration) {
220             // 觸發event事件
221             if (this.preCallApi()) {
222                 if (category && action) {
223                     var time = new Date().getTime();
224                     var event = {};
225                     event[this.columns.eventName] = this.keys.eventDurationEvent;
226                     event[this.columns.category] = category;
227                     event[this.columns.action] = action;
228                     if (map) {
229                         // map若是不爲空,進行內容的添加
230                         for ( var k in map) {
231                             // 循環key
232                             if (k && map[k]) {
233                                 // 當key和value不爲空的時候,進行添加操做
234                                 event[this.columns.kv + k] = map[k]; // key添加前綴"kv_"
235                             }
236                         }
237                     }
238                     if (duration) {
239                         event[this.columns.duration] = duration; // 當duration不爲0的時候進行添加
240                     }
241                     this.setCommonColumns(event); // 設置公用columns
242                     this.sendDataToServer(this.parseParam(event)); // 最終發送編碼後的數據ss
243                     this.updatePreVisitTime(time);
244                 } else {
245                     this.log("category和action不能爲空");
246                 }
247             }
248         },
249 
250         /**
251          * 執行對外方法前必須執行的方法
252          */
253         preCallApi : function() {
254             if (this.isSessionTimeout()) {
255                 // 若是爲true,表示須要新建
256                 this.startSession();
257             } else {
258                 this.updatePreVisitTime(new Date().getTime());
259             }
260             return true;
261         },
262 
263         sendDataToServer : function(data) {
264             // 發送數據data到服務器,其中data是一個字符串
265             // TODO:發送之前發送失敗的數據
266             var that = this;
267             var i2 = new Image(1, 1);
268             i2.onerror = function() {
269                 // 這裏能夠進行重試操做
270                 // 當請求失敗的狀況下,執行這塊的代碼,能夠將數據保存到local stroage中,下次再從新發送數據
271             };
272             // 給定圖片的請求url
273             i2.src = this.clientConfig.serverUrl + "?" + data;
274         },
275 
276         /**
277          * 往data中添加發送到日誌收集服務器的公用部分
278          */
279         setCommonColumns : function(data) {
280             data[this.columns.version] = this.clientConfig.ver;
281             data[this.columns.platform] = "website";
282             data[this.columns.sdk] = "js";
283             data[this.columns.uuid] = this.getUuid(); // 設置用戶id
284             data[this.columns.memberId] = this.getMemberId(); // 設置會員id
285             data[this.columns.sessionId] = this.getSid(); // 設置sid
286             data[this.columns.clientTime] = new Date().getTime(); // 設置客戶端時間
287             data[this.columns.language] = window.navigator.language; // 設置瀏覽器語言
288             data[this.columns.userAgent] = window.navigator.userAgent; // 設置瀏覽器類型
289             data[this.columns.resolution] = screen.width + "*" + screen.height; // 設置瀏覽器分辨率
290         },
291 
292         /**
293          * 建立新的會員,並判斷是不是第一次訪問頁面,若是是,進行launch事件的發送。
294          */
295         createNewSession : function() {
296             var time = new Date().getTime(); // 獲取當前操做時間
297             // 1. 進行會話更新操做
298             var sid = this.generateId(); // 產生一個session id
299             this.setSid(sid);
300             this.updatePreVisitTime(time); // 更新最近訪問時間
301             // 2. 進行uuid查看操做
302             if (!this.getUuid()) {
303                 // uuid不存在,先建立uuid,而後保存到cookie,最後觸發launch事件
304                 var uuid = this.generateId(); // 產品uuid
305                 this.setUuid(uuid);
306                 this.onLaunch(); // 觸發launch事件
307             }
308         },
309 
310         /**
311          * 參數編碼返回字符串
312          */
313         parseParam : function(data) {
314             var params = "";
315             for ( var e in data) {
316                 if (e && data[e]) {
317                     // 對key和value進行編碼操做
318                     params += encodeURIComponent(e) + "="
319                             + encodeURIComponent(data[e]) + "&";
320                 }
321             }
322             if (params) {
323                 return params.substring(0, params.length - 1);
324             } else {
325                 return params;
326             }
327         },
328 
329         /**
330          * 產生uuid<br/>
331          * UUID的產生邏輯,能夠參考Java中UUID的生產代碼
332          */
333         generateId : function() {
334             var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
335             var tmpid = [];
336             var r;
337             tmpid[8] = tmpid[13] = tmpid[18] = tmpid[23] = '-';
338             tmpid[14] = '4';
339 
340             for (i = 0; i < 36; i++) {
341                 if (!tmpid[i]) {
342                     r = 0 | Math.random() * 16;
343                     tmpid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
344                 }
345             }
346             return tmpid.join('');
347         },
348 
349         /**
350          * 判斷這個會話是否過時,查看當前時間和最近訪問時間間隔時間是否小於this.clientConfig.sessionTimeout<br/>
351          * 若是是小於,返回false;不然返回true。
352          */
353         isSessionTimeout : function() {
354             var time = new Date().getTime();
355             var preTime = CookieUtil.get(this.keys.preVisitTime);
356             if (preTime) {
357                 // 最近訪問時間存在,那麼進行區間判斷
358                 return time - preTime > this.clientConfig.sessionTimeout * 1000;
359             }
360             return true;
361         },
362 
363         /**
364          * 更新最近訪問時間
365          */
366         updatePreVisitTime : function(time) {
367             CookieUtil.setExt(this.keys.preVisitTime, time);
368         },
369 
370         /**
371          * 打印日誌
372          */
373         log : function(msg) {
374             console.log(msg);
375         },
376 
377     };
378 
379     // 對外暴露的方法名稱
380     window.__AE__ = {
381         startSession : function() {
382             tracker.startSession();
383         },
384         onPageView : function() {
385             tracker.onPageView();
386         },
387         onChargeRequest : function(orderId, name, currencyAmount, currencyType,
388                 paymentType) {
389             tracker.onChargeRequest(orderId, name, currencyAmount,
390                     currencyType, paymentType);
391         },
392         onEventDuration : function(category, action, map, duration) {
393             tracker.onEventDuration(category, action, map, duration);
394         },
395         setMemberId : function(mid) {
396             tracker.setMemberId(mid);
397         }
398     };
399 
400     // 自動加載方法
401     var autoLoad = function() {
402         // 進行參數設置
403         var _aelog_ = _aelog_ || window._aelog_ || [];
404         var memberId = null;
405         for (i = 0; i < _aelog_.length; i++) {
406             _aelog_[i][0] === "memberId" && (memberId = _aelog_[i][1]);
407         }
408         // 根據是給定memberid,設置memberid的值
409         memberId && __AE__.setMemberId(memberId);
410         // 啓動session
411         __AE__.startSession();
412     };
413 
414     // 調用
415     autoLoad();
416 })();

 

2.同時在access.log收集日誌

 

 

三:JAVA SDK

1.原理圖

  

2.程序的重點

  將日誌數據發送到隊列

  取數據,將數據發送到nginx服務器

 

3.程序AnalyticsEngineSDK

  1 package com.ibeifeng.sdk.java.logmake;
  2 
  3 import java.io.UnsupportedEncodingException;
  4 import java.net.URLEncoder;
  5 import java.util.HashMap;
  6 import java.util.Map;
  7 import java.util.logging.Level;
  8 import java.util.logging.Logger;
  9 
 10 /**
 11  * 分析引擎sdk java服務器端數據收集
 12  * 
 13  * @author ibeifeng
 14  * @version 1.0
 15  *
 16  */
 17 public class AnalyticsEngineSDK {
 18     // 日誌打印對象
 19     private static final Logger log = Logger.getGlobal();
 20     // 請求url的主體部分
 21     public static final String accessUrl = "http://linux-hadoop3.ibeifeng.com/BEIfeng.gif";
 22     private static final String platformName = "java_server";
 23     private static final String sdkName = "jdk";
 24     private static final String version = "1";
 25 
 26     /**
 27      * 觸發訂單支付成功事件,發送事件數據到服務器
 28      * 
 29      * @param orderId
 30      *            訂單支付id
 31      * @param memberId
 32      *            訂單支付會員id
 33      * @return 若是發送數據成功(加入到發送隊列中),那麼返回true;不然返回false(參數異常&添加到發送隊列失敗).
 34      */
 35     public static boolean onChargeSuccess(String orderId, String memberId) {
 36         try {
 37             if (isEmpty(orderId) || isEmpty(memberId)) {
 38                 // 訂單id或者memberid爲空
 39                 log.log(Level.WARNING, "訂單id和會員id不能爲空");
 40                 return false;
 41             }
 42             // 代碼執行到這兒,表示訂單id和會員id都不爲空。
 43             Map<String, String> data = new HashMap<String, String>();
 44             data.put("u_mid", memberId);
 45             data.put("oid", orderId);
 46             data.put("c_time", String.valueOf(System.currentTimeMillis()));
 47             data.put("ver", version);
 48             data.put("en", "e_cs");
 49             data.put("pl", platformName);
 50             data.put("sdk", sdkName);
 51             // 建立url
 52             String url = buildUrl(data);
 53             // 發送url&將url加入到隊列
 54             SendDataMonitor.addSendUrl(url);
 55             return true;
 56         } catch (Throwable e) {
 57             log.log(Level.WARNING, "發送數據異常", e);
 58         }
 59         return false;
 60     }
 61 
 62     /**
 63      * 觸發訂單退款事件,發送退款數據到服務器
 64      * 
 65      * @param orderId
 66      *            退款訂單id
 67      * @param memberId
 68      *            退款會員id
 69      * @return 若是發送數據成功,返回true。不然返回false。
 70      */
 71     public static boolean onChargeRefund(String orderId, String memberId) {
 72         try {
 73             if (isEmpty(orderId) || isEmpty(memberId)) {
 74                 // 訂單id或者memberid爲空
 75                 log.log(Level.WARNING, "訂單id和會員id不能爲空");
 76                 return false;
 77             }
 78             // 代碼執行到這兒,表示訂單id和會員id都不爲空。
 79             Map<String, String> data = new HashMap<String, String>();
 80             data.put("u_mid", memberId);
 81             data.put("oid", orderId);
 82             data.put("c_time", String.valueOf(System.currentTimeMillis()));
 83             data.put("ver", version);
 84             data.put("en", "e_cr");
 85             data.put("pl", platformName);
 86             data.put("sdk", sdkName);
 87             // 構建url
 88             String url = buildUrl(data);
 89             // 發送url&將url添加到隊列中
 90             SendDataMonitor.addSendUrl(url);
 91             return true;
 92         } catch (Throwable e) {
 93             log.log(Level.WARNING, "發送數據異常", e);
 94         }
 95         return false;
 96     }
 97 
 98     /**
 99      * 根據傳入的參數構建url
100      * 
101      * @param data
102      * @return
103      * @throws UnsupportedEncodingException
104      */
105     private static String buildUrl(Map<String, String> data) throws UnsupportedEncodingException {
106         StringBuilder sb = new StringBuilder();
107         sb.append(accessUrl).append("?");
108         for (Map.Entry<String, String> entry : data.entrySet()) {
109             if (isNotEmpty(entry.getKey()) && isNotEmpty(entry.getValue())) {
110                 // key和value不爲空
111                 sb.append(entry.getKey().trim()).append("=").append(URLEncoder.encode(entry.getValue().trim(), "utf-8"))
112                         .append("&");
113                 // 解碼
114                 // URLDecoder.decode("須要解碼的內容", "utf-8");
115             }
116         }
117         return sb.substring(0, sb.length() - 1);// 去掉最後&
118     }
119 
120     /**
121      * 判斷字符串是否爲空,若是爲空,返回true。不然返回false。
122      * 
123      * @param value
124      * @return
125      */
126     private static boolean isEmpty(String value) {
127         return value == null || value.trim().isEmpty();
128     }
129 
130     /**
131      * 判斷字符串是否非空,若是不是空,返回true。若是是空,返回false。
132      * 
133      * @param value
134      * @return
135      */
136     private static boolean isNotEmpty(String value) {
137         return !isEmpty(value);
138     }
139 }

 

4.程序SendDataMonitor

  1 package com.ibeifeng.sdk.java.logmake;
  2 
  3 import java.io.BufferedReader;
  4 import java.io.IOException;
  5 import java.io.InputStreamReader;
  6 import java.net.HttpURLConnection;
  7 import java.net.URL;
  8 import java.util.concurrent.BlockingQueue;
  9 import java.util.concurrent.LinkedBlockingQueue;
 10 import java.util.logging.Level;
 11 import java.util.logging.Logger;
 12 
 13 /**
 14  * 發送url數據的監控者,用於啓動一個單獨的線程來發送數據
 15  * 
 16  * @author ibeifeng
 17  *
 18  */
 19 public class SendDataMonitor {
 20     // 日誌記錄對象
 21     private static final Logger log = Logger.getGlobal();
 22     // 隊列,用戶存儲發送url, 併發控制的Int.maxSize大小的阻塞隊列
 23     private BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
 24     // 用於單列的一個類對象
 25     private static SendDataMonitor monitor = null;
 26 
 27     private SendDataMonitor() {
 28         // 私有構造方法,進行單列模式的建立
 29     }
 30 
 31     /**
 32      * 獲取單例的monitor對象實例
 33      * 
 34      * @return
 35      */
 36     public static SendDataMonitor getSendDataMonitor() {
 37         if (monitor == null) {
 38             synchronized (SendDataMonitor.class) {
 39                 if (monitor == null) {
 40                     monitor = new SendDataMonitor();
 41 
 42                     Thread thread = new Thread(new Runnable() {
 43 
 44                         @Override
 45                         public void run() {
 46                             // 線程中調用具體的處理方法
 47                             SendDataMonitor.monitor.run();
 48                         }
 49                     });
 50                     // 測試的時候,不設置爲守護模式
 51                     // thread.setDaemon(true);
 52                     thread.start();
 53                 }
 54             }
 55         }
 56         return monitor;
 57     }
 58 
 59     /**
 60      * 添加一個url到隊列中去
 61      * 
 62      * @param url
 63      * @throws InterruptedException
 64      */
 65     public static void addSendUrl(String url) throws InterruptedException {
 66         getSendDataMonitor().queue.put(url);
 67     }
 68 
 69     /**
 70      * 具體執行發送url的方法
 71      * 
 72      */
 73     private void run() {
 74         while (true) {
 75             try {
 76                 // take 方法是阻塞方法,隊列上有數據則取出,隊列上沒有數據則等待
 77                 String url = this.queue.take();
 78                 // 正式的發送url
 79                 HttpRequestUtil.sendData(url);
 80             } catch (Throwable e) {
 81                 log.log(Level.WARNING, "發送url異常", e);
 82             }
 83         }
 84     }
 85 
 86     /**
 87      * 內部類,用戶發送數據的http工具類
 88      * 
 89      * @author ibeifeng
 90      *
 91      */
 92     public static class HttpRequestUtil {
 93         /**
 94          * 具體發送url的方法
 95          * 
 96          * @param url
 97          * @throws IOException
 98          */
 99         public static void sendData(String url) throws IOException {
100             HttpURLConnection con = null;
101             BufferedReader in = null;
102 
103             try {
104                 URL obj = new URL(url); // 建立url對象
105                 con = (HttpURLConnection) obj.openConnection(); // 打開url鏈接
106                 // 設置鏈接參數
107                 con.setConnectTimeout(5000); // 鏈接過時時間
108                 con.setReadTimeout(5000); // 讀取數據過時時間
109                 con.setRequestMethod("GET"); // 設置請求類型爲get
110 
111                 System.out.println("發送url:" + url);
112                 // 發送鏈接請求
113                 in = new BufferedReader(new InputStreamReader(con.getInputStream()));
114                 // TODO: 這裏考慮是否能夠
115             } finally {
116                 try {
117                     if (in != null) {
118                         in.close();
119                     }
120                 } catch (Throwable e) {
121                     // nothing
122                 }
123                 try {
124                     con.disconnect();
125                 } catch (Throwable e) {
126                     // nothing
127                 }
128             }
129         }
130     }
131 }

 

5.測試

  

 

 6.結果

  

7.程序Test

 1 package com.ibeifeng.sdk.java.logmake.test;
 2 
 3 import java.util.HashSet;
 4 import java.util.Random;
 5 import java.util.Set;
 6 
 7 import com.ibeifeng.sdk.java.logmake.AnalyticsEngineSDK;
 8 
 9 public class Test {
10     private static Random random = new Random(System.currentTimeMillis());
11     private static Set<Order> orders = new HashSet<>();
12 
13     public static void main(String[] args) throws InterruptedException {
14         Order order = null; 
15         while (true) {
16             order = getSuccessOrder();
17             // 發送訂單付款行爲數據
18             AnalyticsEngineSDK.onChargeSuccess(order.orderId, order.memberId);
19             Thread.sleep(random.nextInt(500));
20             if (random.nextInt(100) > 75) {
21                 // 25%的訂單發生退款行爲
22                 order = getRefundOrder();
23                 if (order != null) {
24                     // 發送訂單退款行爲數據
25                     AnalyticsEngineSDK.onChargeRefund(order.orderId, order.memberId);
26                     Thread.sleep(random.nextInt(500));
27                 }
28             }
29         }
30     }
31 
32     private static Order getSuccessOrder() {
33         while (true) {
34             int orderId = random.nextInt(Math.max(200000, orders.size() * 2));
35             Order order = new Order();
36             order.orderId = "orderid" + orderId;
37             if (!orders.contains(order)) {
38                 // 該order是一個新的order對象
39                 order.memberId = "ibeifeng" + random.nextInt(1000);
40                 orders.add(order);
41                 return order;
42             }
43         }
44     }
45 
46     private static Order getRefundOrder() {
47         int count = 0;
48         Order[] os = orders.toArray(new Order[0]);
49         while (true) {
50             count++;
51             int index = random.nextInt(os.length); // 獲取下標位置
52             Order order = os[index]; // 獲取對應下標位置的數據
53             if (!order.refund) {
54                 order.refund = true; // 設置爲已經退款操做
55                 return order;
56             } else if (count >= os.length) {
57                 // 設置最多重試次數
58                 return null;
59             }
60         }
61     }
62 
63     static class Order {
64         public String orderId;
65         public String memberId;
66         public boolean refund = false;
67 
68         @Override
69         public int hashCode() {
70             final int prime = 31;
71             int result = 1;
72             result = prime * result + ((orderId == null) ? 0 : orderId.hashCode());
73             return result;
74         }
75 
76         @Override
77         public boolean equals(Object obj) {
78             if (this == obj)
79                 return true;
80             if (obj == null)
81                 return false;
82             if (getClass() != obj.getClass())
83                 return false;
84             Order other = (Order) obj;
85             if (orderId == null) {
86                 if (other.orderId != null)
87                     return false;
88             } else if (!orderId.equals(other.orderId))
89                 return false;
90             return true;
91         }
92     }
93 }

 

8.測試

  

相關文章
相關標籤/搜索