通過了不知道多少個小時的coding,姑且算是把代碼大約實現結束了,因爲某些緣由不得不入門全棧開發。雖然以前有過全棧開發的經驗,可是都是基於python後端,本次使用java作後臺仍是遇到了不小的麻煩。簡單梳理一下我認爲咱們組作的好與很差的地方吧。html
0. 代碼複用性前端
本次代碼重寫了後臺,能夠說是極大的提高了工做量,因爲本來的代碼實現計算功能幾乎是重寫了一個編譯器,難度過高,所以決定改用二叉樹做爲數據結構,將符號與數字做爲節點插入樹中,這樣只要節點排布不相同,所遍歷出的樹也就不相同了,能夠說是將查重問題和計算問題同時解決了。值得一提的是,這樣的數據結構的好處是經過中序遍歷,以上兩個問題能夠很高效的解決,可是也暴露出了以前代碼複用性太差的問題,偷懶不可取呀,每一次的程序都應該認真設計,構思後,再開始動手,從根本上提高程序的可擴展性。應當在以後的開發中引覺得戒,簡單附一下數據結構:java
1 package group_work; 2 3 public class Node { 4 Node m_node_left; 5 Node m_node_right; 6 int m_op_num; 7 String m_operate; 8 private All get; 9 10 String symbol_double[] = new String[] {"+","-","*","/"}; 11 String symbol_single[] = new String[] {"^0.5","^2","sin","cos","tan"}; 12 13 boolean is_oper = false;//false 表示是數字 true表示是操做符 14 boolean is_single = false; // false 表示是雙操做數 true表示是單操做數 15 16 public Node(int num,String oper) 17 { 18 // TODO Auto-generated constructor stub 19 this.m_op_num = num; 20 this.m_operate = oper; 21 } 22 23 24 public void display() 25 { 26 if (is_oper) { 27 System.out.print(this.m_operate); 28 } 29 else { 30 System.out.print(this.m_op_num); 31 } 32 } 33 34 public String toString() 35 { 36 String mem_temp; 37 if (is_oper) { 38 mem_temp = this.m_operate; 39 } 40 else { 41 mem_temp = String.valueOf(this.m_op_num); 42 } 43 return mem_temp; 44 } 45 46 public static Node Insert(Node root,String te,int num) //建樹 47 { 48 if(root == null) 49 { 50 root = new Node(num--,te); 51 } 52 else if(root.is_oper) 53 { 54 if(root.m_node_left == null) 55 { 56 root.m_node_left = Insert(root.m_node_left,te,num--); 57 } 58 else if(root.m_node_right == null && !root.is_single) 59 { 60 root.m_node_right = Insert(root.m_node_right,te,num--); 61 } 62 } 63 return root; 64 } 65 66 }
1 package group_work; 2 3 public class BinTree { 4 Node root; 5 int status; 6 static private All get; 7 8 static String symbol_double[] = new String[] {"+","-","*","/"}; 9 static String symbol_single[] = new String[] {"^0.5","^2","sin","cos","tan"}; 10 11 BinTree(int status) { 12 // TODO Auto-generated constructor stub 13 root.m_node_left = null; 14 root.m_node_right = null; 15 this.status = status; 16 } 17 18 public BinTree() { 19 // TODO Auto-generated constructor stub 20 } 21 22 int symFlag = 0; //sum爲最後獲得的結果 23 double sum = 0,operNow = 0; 24 25 public static String CreateSymbol(int status) 26 { 27 String opera; 28 if(status == 1) 29 { 30 int num = get.RandSel(0,4); 31 opera = symbol_double[num]; 32 } 33 34 else if(status == 2) 35 { 36 int num = get.RandSel(0,6); 37 if(num < 4) 38 { 39 opera = symbol_double[num]; 40 } 41 else 42 { 43 num -= 4; 44 opera = symbol_single[num]; 45 } 46 } 47 48 else 49 { 50 int num = get.RandSel(0,7); 51 if(num < 4) 52 { 53 opera = symbol_double[num]; 54 } 55 else 56 { 57 num -= 2; 58 opera = symbol_single[num]; 59 } 60 } 61 return opera; 62 } 63 64 public Node CreateTree(Node root,int begin,int end) 65 { 66 Node.Insert(root,CreateSymbol(status),get.RandSel(begin, end)); 67 return root; 68 } 69 public void TravleInOrder(Node root) 70 { 71 if (root.m_node_left != null) 72 { 73 TravleInOrder(root.m_node_left); 74 } 75 76 if(!root.is_oper) //若是爲數字則已經是根節點,返回 77 { 78 operNow = root.m_op_num; 79 if(sum == 0) //賦予初始值 80 { 81 sum = operNow; 82 } 83 } 84 85 else //若爲符號,則獲取對應編號值以進行後續操做獲得運算結果 86 { 87 88 if(root.m_operate == "+") 89 { 90 symFlag = 1; 91 } 92 else if(root.m_operate == "-") 93 { 94 symFlag = 2; 95 } 96 else if(root.m_operate == "*") 97 { 98 symFlag = 3; 99 } 100 else if(root.m_operate == "/") 101 { 102 symFlag = 4; 103 } 104 else if(root.m_operate == "sin") 105 { 106 operNow = Math.sin(operNow); 107 } 108 else if(root.m_operate == "cos") 109 { 110 operNow = Math.cos(operNow); 111 } 112 else if(root.m_operate == "tan") 113 { 114 operNow = Math.tan(operNow); 115 } 116 else if(root.m_operate == "^0.5") 117 { 118 operNow = Math.sqrt(operNow); 119 } 120 else if(root.m_operate == "^2") 121 { 122 operNow = operNow * operNow; 123 } 124 } 125 126 if (root.m_node_right != null) 127 { 128 TravleInOrder(root.m_node_right); 129 } 130 131 if(symFlag != 0) 132 { 133 if(symFlag == 1) 134 { 135 sum += operNow; 136 } 137 else if(symFlag == 2) 138 { 139 sum -= operNow; 140 } 141 else if(symFlag == 3) 142 { 143 sum *= operNow; 144 } 145 else if(symFlag == 4) 146 { 147 sum /= operNow; 148 } 149 symFlag = 0; 150 } 151 } 152 153 154 }
1. 短信接口node
此次開發中的一個重難點是使用短信接口,最初因爲簽名問題一直難以直接申請到Key,在同窗的幫助下終於將key的問題解決。表示感謝!python
這裏涉及到一個實時驗證以及先後端交互的問題。咱們分開兩個部分來開。首先是實時驗證部分,這一部分主要是對form當中的input進行實時校驗,那麼顯然須要利用js對其緩存區進行監聽。因爲手機號都是以固定格式,十一位數字組成,那麼這裏顯然能夠利用正則表達式來對其進行檢索判斷,同時須要注意的是,爲了不用戶不停點擊發送按鈕,致使短信API在一段時間內屢次調用影響體驗,這裏要對button進行禁用,經過setInterval來進行定時器調用,對該函數每隔1秒render一次,這樣就能夠動態提醒用戶還有多少秒能夠從新進行發送,提高了用戶體驗。ajax
爲了保證頁面的美觀度,我選擇了使用bootstrap來進行響應式佈局,以適配移動端。同時,使用jQuery作粘合,保證代碼的簡潔性。正則表達式
按鈕按下後,會優先檢查手機號輸入是否合法,若不合法會提示從新輸入,合法會發送驗證碼,同時ban掉button。若是驗證碼與原值匹配,後端返回值爲真,則進行下一步跳轉,這裏演示一下輸入的檢查。json
附,表單驗證與按鈕禁用代碼。bootstrap
1 var phoneReg = /(^1[3|4|5|7|8]\d{9}$)|(^09\d{8}$)/;//手機號正則 2 var count = 60; //間隔函數,1秒執行 3 var InterValObj1; //timer變量,控制時間 4 var curCount1;//當前剩餘秒數 5 /*第一*/ 6 function sendMessage1() { 7 curCount1 = count; 8 var phone = $.trim($('#phone1').val()); 9 if (!phoneReg.test(phone)) { 10 alert(" 請輸入有效的手機號碼"); 11 return false; 12 } 13 //設置button效果,開始計時 14 $("#btnSendCode1").attr("disabled", "true"); 15 $("#btnSendCode1").val( + curCount1 + "秒再獲取"); 16 InterValObj1 = window.setInterval(SetRemainTime1, 1000); //啓動計時器,1秒執行一次 17 //向後臺發送處理數據 18 19 } 20 function SetRemainTime1() { 21 if (curCount1 == 0) { 22 window.clearInterval(InterValObj1);//中止計時器 23 $("#btnSendCode1").removeAttr("disabled");//啓用按鈕 24 $("#btnSendCode1").val("從新發送"); 25 } 26 else { 27 curCount1--; 28 $("#btnSendCode1").val( + curCount1 + "秒再獲取"); 29 } 30 } 31 32 /*提交*/ 33 function binding(){ 34 alert(1) 35 }
2. 後臺後端
後臺當中主要是利用jsp與前端的ajax數據傳輸,這裏要提到一個概念,叫作 服務器-客戶端 模式。如今的網頁中大多數的數據交互都是經過發送請求與響應請求完成的,那麼研究其中的過程就對代碼的構建尤其重要。剛剛咱們說到,在html頁面所包含的表單中會向後臺傳送數據,這裏實際上就是提交了一個請求,也就是觸發了submit事件,當服務器(後端)收到這個請求後,經過response應答這個請求,同時回傳數據給前端,這樣數據就成功的在這兩端進行了交互。
那麼咱們先來看看前端的ajax幹了什麼。ajax(Asynchronous Javascript And XML)實質上就是異步JavaScript與XML,這裏尤爲要注意一點,ajax是異步操做!異步操做!異步的意思就是,他沒有你想象中那麼美好,並非真的在順序執行的。這也是我在另外一個項目中遇到的問題,因爲它是異步操做,有時候你很難判斷數據和下一步操做究竟哪一個能先到達,有時候很奇異的是你ajax所回傳的數據可能正是你前端要先load進來才能採起下一步操做的數據,那麼若是這個時候數據還沒拿到是否是就涼了呢?有一種解決辦法就是經過回調函數來進行解決。所謂回調函數實際上就是當一個函數執行完成後所採起的行動,有嚴格意義上的順序關係。那麼這樣就能夠鎖定操做的順序了,把另外函數做爲函數指針傳入,ajax返回的數據做爲參數,就能夠實現咱們所想要的目標效果,這裏給出一個簡單的demo。
1 function getNameList(callback) { 2 $.ajax({ 3 url:"/get_person", 4 data:{}, 5 dataType:"json" 6 }) 7 .done(function(data_p){ 8 callback(data_p) 9 data_all = data_p 10 }) 11 } 12 13 window.onload = function () { 14 getNameList(init) 15 }
其餘關於ajax的知識,其實大多都是計算機網絡的基本知識,詳情參考API,並不在此贅述。
接下來咱們看看後端,剛剛提到說後端須要接受請求,那麼這時候參數的對應就顯得較爲重要。一般有兩種數據傳輸的方式,GET方式與POST方式,其中獲取參數咱們一般使用request.getParameter("amount")這樣的方式,其中的參數表示須要獲取的鍵,這裏有鍵天然能得到其相應的值。
好比這裏咱們實現的題目總數輸入中,這段代碼就很好的詮釋了以上的概念:
1 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 2 // 語言設置 3 response.setCharacterEncoding("UTF-8"); 4 response.setContentType("text/html;charset=UTF-8"); 5 6 // 數目設置 7 amount = Integer.valueOf(request.getParameter("amount")); 8 for (int i = 0; i < amount; i++) { 9 calList[i].status = status; 10 calList[i].CreateTree(calList[i].root, 0, 5); 11 } 12 } 13 14 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 15 doGet(request, response); 16 } 17 18 }
以上是咱們組的合做中的重點與難點,後續可能還會有更新。