同樣,還是一次工作上遇到的問題的記錄,當時也是搞了挺久才搞出來的,雖然不太完美,但是誤差方面在我的項目里還算可以接受,哪位老哥有更好的辦法還請指導下,哪怕評論里留個網頁鏈接我去看也好,多謝了。
具體問題描述大致如下:
客戶需要app能查詢出所有訂單,分頁並且按時間倒序排列,現在所有的消費訂單數據在我們自己的數據庫里,而所有的充值訂單數據其實在第三方那里(其實我們自己也記錄了一筆,但是數據結果不可靠,因此還是要取用對方的),關於從第三方獲取數據的參數概括是(用戶唯一標識,每頁顯示行數,當前頁數),即(userId,pageSize,pageNo),其中pageSize要求小於50。
經過思考,需要解決的問題主要在於:
1.如何從第三方獲取我需要的數據
2.整合我們庫里的數據,第三方獲取的數據,進行時間倒序排列,並返回給app
實際上第二點很好解決,只要寫一個排序類,對整合后的數據進行排序即可,最主要難點在於第一點,如何確定調取第三方接口的入參pageSize和pageNo,然后還要把之前已經展示過的數據排除掉。
具體解決方法如下:
1.首先,我用了cache,用於記錄app已展示的(消費記錄數)(充值記錄數),即(我方庫數據展示量)(第三方數據展示量),暫定參數為own和other,當app端傳的頁數為第一頁時,將這兩個數據都置為0.
2.查詢接下來需要展示的數據中,我方的數據,這點沒什么好說的,正常的查自己數據庫即可,需要查出來的量為own<rownum<own+appPageSize,其中appPageSize是指app的入參,app端的頁顯示行數
3.然后查詢需要展示的數據中,第三方的數據,關於確定調取第三方接口入參的方法如下:
1 /** 2 * 獲取第三方訂單查詢接口所需要的參數 3 * @param start 起始數據量 4 * @param end 結束數據量 5 * @param size 展示數據量 6 * @return 7 * Map,包含兩個參數,pagenum頁數,pagesize頁顯示行數 8 */ 9 public static Map<String,Integer> getWdPara(int start,int end,int size){ 10 Map<String,Integer> map=new HashMap<>(); 11 if (start<size||start/size<1) { 12 map.put("pagenum", 1); 13 map.put("pagesize", 10*((end/10)+1)); 14 }else{ 15 if (start/size==end/size) { 16 map.put("pagenum", (end/size)+1); 17 map.put("pagesize", size); 18 }else { 19 map=getWdPara(start, end, size+1); 20 } 21 } 22 return map; 23 }
其中三個參數的關系是end=start+size,實際上start入參的值就是other,而size入參的值就是appPageSize。而出參的兩個參數就分別是調取第三方時候的入參pageSize和pageNo了。關於如何確定這個方法可以獲取想要的參數,說起來有點繞,我數學也不太好,當時打了挺久的草稿,參照如下,如果看不懂直接跳過就好。。。因為我自己也經常忘記什么意思:
默認app端展示數據量為10條,所以從第三方中獲取的數據需要包含other+10條,因為根據時間倒序,這中間存在沒有數據是消費數據,全是充值數據的情況,即所有展示數據均來自於第三方。
第三方數據的起始-截止數據量 pageSize參數,即s pageNo參數,即n 實際取到的數據量
8-18 20 1 1-20
18-28 15 2 15-30
28-38 20 2 20-40
。。。
一開始是這樣草稿打下去的,后來找規律后發現,其實就和查自己數據庫一樣,保證查到的數據包含起始數據和終止數據即可,即
( 頁數-1)*頁顯示行數>起始數據,頁數*頁顯示行數>終止數據
然后進行幾次舉例驗證后,就得出上述獲取參數的方法了。
至此,最難的一步已經完成了,即已經獲取到所有需要的數據了。
4.然后進行下一步,需要去除掉之前已經展示過了的數據,就如上面例子,我們獲取到的數據量,其實是大於需要的數據量,有一部分數據可能之前已經展示了,因此在這里需要將之前展示了的數據去除掉,代碼如下
1 /** 2 * 處理訂單數據,排除之前顯示過的數據 3 * @param dataList 待處理的list 4 * @param start 數據起始 5 * @param size 頁顯示行數 6 */ 7 public static void dealList(List<Map<String, String>> dataList,int start,int size){ 8 int removeNum=start%size; 9 for (int i = 0; i < removeNum; i++) { 10 dataList.remove(0); 11 } 12 }
即起始數據除以頁顯示行數,取余數,然后獲取到的數據量從前往后刪除這個余數量的數據即可,這個余數量即之前已經展示用過的數據量。和上面獲取參數一樣,這個計算方法,也是我自己寫了好幾個例子,然后找規律寫出來的。。。數學不好,見諒,我也不知道邏輯上該怎么解釋,反正根據例子找規律,發現這樣寫沒問題。
5.再然后就沒啥問題了,要展示的充值數據,消費數據都已經全部獲取到了,只要將一些參數名稱處理下,確保保持一致,放在一個list里面,然后寫個排序方法,根據訂單時間進行倒序,排完序以后,獲取前appPageSize個數據返回給前端即可,排序代碼如下:
1 /** 2 * 數據進行排序,按照時間倒序排序 3 * @param list 4 */ 5 @SuppressWarnings("unchecked") 6 public static void sortTimeMethod(List<Map<String,String>> list){ 7 Comparator comp= new Comparator<Map<String, String>>(){ 8 //返回值大於0時,兩者交換順序 9 @Override 10 public int compare(Map<String, String> p1,Map<String, String> p2){ 11 String p1Date=Tools.processNull(p1.get("order_date")); 12 String p2Date=Tools.processNull(p2.get("order_date")); 13 if ("".equals(p1Date) 14 ||"".equals(p2Date)) { 15 return 0; 16 }else { 17 //如果o1時間早於等於o2時間,則o1排在后面 18 if (!DateUtil.formatDate(p1Date).after(DateUtil.formatDate(p2Date))) { 19 return 1; 20 }else { 21 return -1; 22 } 23 } 24 } 25 }; 26 Collections.sort(list, comp); 27 }
6.當然,這時候也別忘記更新cache里面的數據,根據最終返回給前端的數據,判斷有多少消費數據和充值數據,對own和other進行相應的累加。
以上就全部完成。不過就和我之前說的,有誤差,很有局限性,跟我們使用場景有關,因此不是很具備參考性,相關說明如下:
1.我們是APP展示用的,場景中無法跳頁,也就是用戶只能選擇先看第一頁,再看第二頁數據,這樣依次下排,如果存在跳頁,我這個方法應該不行。
2.當用戶在看訂單的同時,無法進行充值或消費操作,進行充值或消費等產生訂單的操作后,重新來查詢必定是從第一頁開始,因此那種查了一會兒,突然增加一條訂單了,這種情況是不會出現的,否則我這方法會存在問題,即cache里的值不准了,導致的結果就是查詢的數據也不准了,有個訂單會展示兩次。
可能看上去條理不是很清晰,有點混亂。。。但是盡力了,其實一開始沒打算寫,后來隔了半個多月,突然發現自己這個代碼看不懂了,然后重新理解了半天,想想這個當初也是自己搞了挺久才弄出來的,怕以后又忘記了,於是此時開始寫這篇隨筆,本身就是隔了半個月后再寫,思路就不是很清晰,結果寫了一小半,客戶又來事情了,於是忙去了。。。然后一段時間沒閑下來,再然后忙着忙着就給忘了。。。。直到今天,已經是半年后了,再次來續寫的時候,腦子就更亂了,強行看着半篇內容加自己原先的代碼,將其續寫完成。主要用處估計也就是以后自己如果遇到相同問題,給自己一個提點,一個思路,防止到時候自己腦子又轉不過來。