前后端數據交互,跳轉


概述

作為一枚菜鳥,前后端交互可是大問題,經常數據交互失敗,不知道怎么跳轉。在這分享一下交互的小心得。

我們不妨先大概了解一下整個訪問流程:

用戶從輸入網址按下回車,交互就已經開始了。

瀏覽器會將請求按照http協議(或者其他https,ftp等)將請求數據封裝包從電腦的端口發出 -> 路由器 -> 運營商(域名解析之類的)-> 目標服務器(可能會有代理,負載均衡等等)

最終從服務器開放的端口,進入到服務器(TCP三次握手和四次揮手,Tomcat之類的,會根據協議的內容進行解析)-> web項目進行具體的邏輯處理 -> 返回數據 -> 瀏覽器接收數據(根據協議內容進行解析

整個過程,協議很重要,因為客戶端和服務器都是通過協議來解析和發送信息的,最常見的http協議,協議頭部的參數常用的哪幾個,有什么影響。

Http協議的簡介,說的很有意思:https://blog.csdn.net/u010256388/article/details/68491509/

還有緩存問題(cookie、session、localstorage、cashe-controller等),不僅提高效率,而且有時候你更改了代碼測試卻沒變化的重要原因https://www.jianshu.com/p/9ed3e8759ce3

相應的后台tomcat的緩存處理:http://www.360doc.com/content/17/0721/17/41344223_673116604.shtml(了解即可)

 

具體到使用分為:前端交互,分為同步和異步。

同步交互

常見的from表單提交(post方式帶參數),URL直接訪問(get方式,有參數在地址欄可見,特殊符號需要轉義,不安全)。

異步交互

關鍵是XMLHttpRequest對象,平時說的ajax只是一種交互模式,並不是什么新技術,其原理就是對XMLHttpRequest的封裝。所以對XMLHttpRequest深入全面的了解可以幫助我們更好的掌握異步交互。

可以看這篇精品文章了解:https://www.jianshu.com/p/b037f71af548,里面涉及到了在傳送過程中各個參數的用法,會觸發的事件,返回值等等很實用的知識。(雖然能設置同步交互,但不推薦)

其中傳輸類型 contentType就非常重要,這個值設置決定了后台怎么去解析http協議。

json交互 

  • 上圖所示,如果格式前后端發送和接收對不上,那是獲取不了數據。如圖的最后一步返回,如果想頁面跳轉,則不需要@ResponseBody,改為返回ModelAndView
  • @RequestBody主要用來接收前端傳遞給后端的json字符串中的數據的(請求體中的數據的);GET方式無請求體,所以使用@RequestBody接收數據時,前端不能使用GET方式提交數據,而是用POST方式進行提交。
  • @RequestParam接收的是key-value里面的參數,所以GET方式的數據和表單提交,可以接收。
  • @RequestBody和@RequestParma的使用知識,更輕松的全面掌握:https://blog.csdn.net/justry_deng/article/details/80972817

前端交互類

前端我創建了兩個工具類,來負責交互。

異步交互類

我把jQuery的ajax進行了封裝,主要是獲取和計算信息,代碼如下:

  1 /*
  2  * 以下為程序錯誤碼
  3  */
  4 //通用的請求失敗,包括未知原因
  5 var EXPECTATION_FAILED = 417;
  6 var EXPECTATION_QUERY = 404;
  7 
  8 /**
  9  * 訪問后台的對象,為ajax封裝
 10  * @constructor
 11  */
 12 var Query = function (url, param, callback, contentType) {
 13     this.url = url;
 14 
 15     //先確認參數存在,如果不存在則創建空map
 16     if (!param) {
 17         param = new Map();
 18     }
 19     //注意,要根據不同的傳輸格式來確定傳輸的值的類型
 20     if (contentType == Query.NOMAL_TYPE) {
 21         this.param = JSON.parse(this._convertParam(param));
 22     } else {
 23         this.param = this._convertParam(param);
 24     }
 25 
 26 
 27     this.callback = callback;
 28     this.contentType = contentType;
 29     //請求超時,默認5秒
 30     this.timeout = 5000;
 31     //是否異步請求,默認異步
 32     this.async = true;
 33 }
 34 
 35 Query.JSON_TYPE = 'application/json';
 36 Query.NOMAL_TYPE = 'application/x-www-form-urlencoded';
 37 
 38 /**
 39  * ajax請求的訪問
 40  * @param url 要訪問的地址
 41  * @param paramMap 傳給后台的Map參數,key為字符串類型
 42  * @param callback 回調函數
 43  * @param contentType 傳輸數據的格式  默認傳輸application/x-www-form-urlencoded格式
 44  */
 45 Query.create = function (url, paramMap, callback) {
 46     return new Query(url, paramMap, callback, Query.NOMAL_TYPE);
 47 }
 48 
 49 Query.createJsonType = function (url, paramMap, callback) {
 50     return new Query(url, paramMap, callback, Query.JSON_TYPE);
 51 }
 52 
 53 /**
 54  * 將ParamMap轉為json格式,目前只支持Map對象,以后會擴展
 55  * @param paramMap
 56  * @private
 57  */
 58 Query.prototype._convertParam = function (param) {
 59 
 60     if (param instanceof Map) {
 61         return strMap2Json(param);
 62     }
 63 }
 64 
 65 /**
 66  * 對ajax回調函數的封裝
 67  * @param callBack
 68  * @private
 69  */
 70 Query.prototype._callback = function (queryResult) {
 71 
 72     //取消加載框
 73     if (this.loadDom) {
 74         $(this.loadDom).remove("#loadingDiv");
 75     }
 76 
 77     //Query對象
 78     var self = queryResult.queryObj;
 79     var data = $.parseJSON(queryResult.responseText);
 80     //記錄請求是否有錯誤
 81     self.queryException = false;
 82     var handleError;
 83 
 84     if (queryResult.status == EXPECTATION_FAILED || queryResult.status == EXPECTATION_QUERY) {
 85         var error = queryResult.responseText;
 86         self.queryException = true;
 87     }
 88 
 89     //調用回調函數,如果返回結果為true,則對於出錯不會默認錯誤處理
 90     if (self.callback instanceof Function) {
 91         handleError = self.callback(data);
 92     }
 93 
 94     //如果出現了異常並且沒有被處理,那么將進行默認錯誤處理
 95     if (self.queryException && !handleError) {
 96         window.location.href = "/system/error/" + error.code + "/" + error.msg;
 97     }
 98 
 99     //如果需要跳轉,則進行跳轉
100     if (data.redirect_url) {
101         window.location.href = data.redirect_url;
102     }
103 }
104 
105 /**
106  * 正式發送ajax
107  * @private
108  */
109 Query.prototype.sendMessage = function () {
110     var self = this;
111     var xhr = $.ajax(
112         {
113             type: "post",
114             url: this.url,
115             contentType: this.contentType,
116             data: this.param,
117             // ajax發送前調用的方法,初始化等待動畫
118             // @param XHR  XMLHttpRequest對象
119             beforeSend: function (XHR) {
120                 //綁定本次請求的queryObj
121                 XHR.queryObj = self;
122                 if (self.beforeSendFunc instanceof Function) {
123                     self.beforeSendFunc(XHR);
124                 }
125 
126                 if (self.loadDom instanceof HTMLElement) {
127                     self.loadDom.innerText = "";
128                     $(self.loadDom).append("<div id='loadingDiv' class='loading'><img src='/image/loading.gif'/></div>");
129                 } else if (self.loadDom instanceof jQuery) {
130                     self.loadDom.empty();
131                     self.loadDom.append("<div id='loadingDiv' class='loading'><img src='/image/loading.gif'/></div>");
132                 }
133             },
134             complete: this._callback,
135             timeout:this.timeout,
136             async:this.async
137         }
138     );
139 
140 }
141 
142 /**
143  * 檢測是否有錯誤,返回ture有錯誤,或者false
144  */
145 Query.prototype.checkEception = function () {
146     return this.queryException;
147 }
148 
149 //------------------------以下為對Query的參數設置---------------------------
150 /**
151  * 在ajax發送前設置參數,可以有加載的動畫,並且請求完成后會自動取消
152  * @param loadDom 需要顯示動畫的dom節點
153  * @param beforeSendFunc ajax發送前的自定義函數
154  */
155 Query.prototype.setBeforeSend = function (loadDom, beforeSendFunc) {
156     this.loadDom = loadDom;
157     this.beforeSendFunc = beforeSendFunc;
158 }
159 
160 /**
161  * 設置超時時間
162  * @param timeout
163  */
164 Query.prototype.setTimeOut = function (timeout) {
165     this.timeout = timeout;
166 }
167 
168 Query.prototype.setAsync = function (async) {
169     this.async = async;
170 }

封裝的好處:

  • 可以省略很多重復的代碼,如$.ajax傳參數那一長串(111-136行)
  • 可以規定統一的前端交互流程,並且修改這個流程也方便。
    1. 根據傳輸類型也對參數進行轉換(20-24行),並且_convertParam()方法能繼續擴展參數類型,直到后面可以把絕大多數參數都轉換成正確的格式(那發送基本不用考慮參數格式了,只要確定傳輸的類型就好)              
    2. 統一回調流程(70-103行)可以對異常做統一處理(ajax)像我這樣跳轉到錯誤頁面,或者有些異步請求返回時需要跳轉,也能統一跳轉
    3. 統一請求發送前的處理(119-133行)可以對請求等待統一的設置等待動畫,最后再回調流程統一取消動畫

同步交互類

from表單創建類,主要是進行有參數傳輸的頁面跳轉,因為直接URL跳轉參數會暴露不安全

 1 /**
 2  * 訪問后台的類,構造form表單來進行post請求
 3  * @param url
 4  * @param paramMap  參數map
 5  * @constructor
 6  */
 7 var QueryForm = function (url,paramMap) {
 8     //form表單的JQ對象
 9     this.form = $("<form></form>");
10     this.form.attr("action",url);
11     this.form.attr("method","post");
12     //遍歷Map
13     for(var [key,value] of paramMap){
14        var inputDom = $("<input/>") ;
15        inputDom.attr("name",key);
16        inputDom.attr("value",value);
17        this.form.append(inputDom);
18     }
19     //必須要放入body里面,不然請求發不出去
20     var bodyDom = $("body");
21     bodyDom.append(this.form);
22     this.sendMessage();
23 
24     //發送完后銷毀
25     this.destroy();
26 }
27 
28 QueryForm.create = function (url, paramMap) {
29     return new QueryForm(url,paramMap);
30 }
31 
32 QueryForm.prototype.sendMessage = function () {
33      this.form.submit();
34 }
35 
36 QueryForm.prototype.destroy =  function () {
37     this.form.remove();
38 }

后端交互類

普通的Controller,在@RequestMapping中填寫正確的路徑,根據前端傳輸的數據類型來獲取參數(見上文),根據邏輯來確定要不要@ResponseBody來返回信息,還是ModelAndView來進行頁面跳轉

路徑

經常404怎么辦,那就是路徑有問題。得先明白,java虛擬機運行的不是java文件而是編譯后的.calss文件,所以最先檢查的是target文件夾下是否有你URL寫的這個文件,是否路徑正確

平時網上看到的classpath,就是指target下的classes文件夾

順帶提一句,如果是eclipse,右鍵點擊新建,你會發現有幾個文件夾可以選

folder:就是普通的文件夾,它和我們window下面使用的文件夾沒有任何區別


source folder:文件夾是一種特別的文件夾,如果你用面向對象的思想去看待這個source folder,那么他是folder的一個子集,作為子集,肯定是有folder的所有功能,而且還有自己特別的功能,他的特別之處,就是在source folder下面的java文件都會被編譯,編譯后的文件會被放在我們設置的某個文件夾下面(一般我們設置成WEB-INF/classes),source folder下面的非java文件會被copy一份放在我們的設置的文件夾下面


package:文件夾也是一種特別的文件夾,他的特別之處在於:他必須存在於source folder下面,上下級通過.來區分,他的路徑最后組成了每一個類的包路徑名

 

所以當出現404,請先檢查路徑,如果是springboot項目,則要遵守一些默認路徑規則,比如模板必須放在templates,靜態文件必須放在static

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM