前言
一位小妹去面試前端,前端leader問了"什么是ajax?",答:“接收后台的數據,然后然后自己填充和渲染樣式”;一位小哥去面試后台,技術經理問了“什么是ajax?”,答:“在不需重新加載整個網頁的情況下,發送異步請求,返回json數據給前端”。准確答案到底是什么?Ajax到底屬於前端還是屬於后端?前端(或者后端)到底需不需要懂得Ajax?Ajax請求與普通的http請求有什么區別?數據庫中的數據通過Ajax請求和普通請求下分別是怎么傳遞到前台的...等等一些問題,似乎需要靜下心來理一理。
MVC篇
最典型的MVC就是JSP + servlet + javabean的模式,不少人的web起點應該也是這個,記得當時看到最多的問題就是JSP和Servlet區別,后來隨着Struts 、Spring MVC等框架出來,MVC被談論的更多了,越來越多的人開始想要深入學習和理解它,同時也有越來越多的問題開始圍繞MVC展開。基本的概念:MVC = Model View Controller = 模型-視圖-控制器,太過於概念化的東西確實不太好理解,也許框架都用了好幾年,一問MVC還是會懵。不過還是Talk is cheap,下面以Spring MVC + jsp的開發過程示例,同時也是數據在普通http請求后從數據庫傳遞到前端的過程。
背景:ssm項目中,將數據庫中TBL_PERSON表的記錄全部獲取,在前端以表格呈現出來,即<table>標簽下(因為自己寫的樣式實在太丑,重點關注過程吧)
1.Controller層關鍵代碼
package com.mmm.web; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.mmm.pojo.Person; import com.mmm.service.PersonService; @Controller @RequestMapping("person") public class PersonController { @Autowired PersonService personService; /** * 框架跳轉頁面默認是forward,也就是請求轉發 * 這里的model設置的屬性,在jsp頁面也能直接通過el表達式獲取 * */ @RequestMapping(value="httplist") public String httplist(Model model) { List<Person> list = personService.selectAll(); model.addAttribute("list", list); return "person/list"; } ...... }
2.jsp頁面
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Person列表</title> </head> <body> <table> <tr> <th>姓名</th> <th>性別</th> </tr> <c:forEach var="i" begin="0" end="${list.size() }"> <tr> <td>${list[i].name }</td> <td>${list[i].gender }</td> </tr> </c:forEach> </table> </body> </html>
3.tomcat啟動項目,地址欄輸入http://localhost:8081/mm-web/person/httplist,即可看到如下頁面,獲取到了數據庫中完整數據
Ajax篇
傳統web開發在沒有應用Ajax技術的時候,往往頁面是用jsp,而這也讓我們看到MVC的不足,視圖與控制器間的過於緊密的連接,每次請求必須經過“控制器->模型->視圖”這個流程,當java腳本 + 各種表達式 + html代碼 +javascript代碼混雜一塊的時候,簡直痛不欲生,代碼可讀性十分差,而且給后面維護和修改代碼的人帶來很大阻礙。再說下Ajax,首先簡單介紹下,Ajax = 異步 Javascript 和 XML,聽名字不難發現,並未涉及到后端java代碼,核心對象XMLHTTPRequest(可擴展超文本傳輸請求),通過它,我們可以在不刷新頁面的情況下,發送異步請求至后台,並獲取后台返回的json數據。說的簡單點,就是不刷新或者跳轉頁面,發送請求然后拿數據,在這里,比較重要的一點,主動權是在前台這邊,前台拿到數據后再根據需求去填充數據內容,渲染樣式,實現頁面效果。而且由於Ajax基於的Javascript屬於前端腳本,並不依賴於jsp環境,頁面寫Html也是可以的。所以下面以Spring MVC + Ajax + jsp示例(這里的ajax采用Jquery寫法,工作中一般也是應用Jquery較多,原生js寫法相較繁瑣一點,這里就不展示了),同時為了區別返回json數據和直接跳轉頁面的區別,在控制器中寫了兩個方法,一個用於跳轉頁面,但並未拿到數據,等頁面載入后,通過js發起Ajax請求到控制層拿到數據,再動態填充到頁面,並且無需刷新頁面,所以后面我們在地址欄輸入地址后,看上去像一次請求,其實一共兩次。
1.Controller層關鍵代碼
package com.mmm.web; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.mmm.pojo.Person; import com.mmm.service.PersonService; @Controller @RequestMapping("person") public class PersonController { @Autowired PersonService personService; /** * 這里接受地址欄請求,僅起到轉發頁面作用,並未傳遞到我們數據庫的內容 * */ @RequestMapping(value="toPage") public String httplist() { return "person/list"; } /** * 這里@ResponseBody代表該方法接受請求后不是跳轉頁面,而是直接返回json數據 * 注意引入json相關jar包,還有spring MVC配置中不要漏掉<mvc:annotation-driven/> * */ @RequestMapping(value="ajaxlist") @ResponseBody public List<Person> ajaxlist() { List<Person> list = personService.selectAll(); return list; } ...... }
2.jsp頁面
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Person列表</title> <!-- 引入Jquery --> <script src="http://code.jquery.com/jquery-1.7.2.min.js"></script> <!-- 編寫腳本 --> <script type="text/javascript"> $(function() { $.ajax({ url: '${pageContext.request.contextPath}/person/ajaxlist', type: 'post', dataType: 'json', success: function(data) {//這里的data代表的就是返回person集合list var html = ""; html += "<tr><th>姓名</th><th>性別</th></tr>"; for(var i in data){ html += "<tr><td>"+data[i].name+"</td><td>"+data[i].gender+"</td></tr>"; } $("table").html(html); } }); }); </script> </head> <body> <table> </table> </body> </html>
3.tomcat啟動項目,地址欄輸入http://localhost:8081/mm-web/person/toPage,即可看到如下頁面,同樣獲取到了數據庫中完整數據(是兩次請求)
關於前后端分離
在傳統的java web項目中,應用MVC框架,Jsp想做的事太多,既有后台數據的處理手法,也要承擔視圖展現的職能,Java代碼、Html、CSS、Javascript、各種表達式、發送請求、接收數據、頁面跳轉...甚至有點全能的感覺,但正是這種全能,讓本該分工明確個的各單位糅雜在一起,給開發也帶來了一些麻煩。使用Ajax,才真正有點分離的感覺,至少我們知道html、CSS、Js是屬於前端版塊,后台專注於業務邏輯和數據處理,讓前台拿到結果,然后填充內容或者進行局部動態更新,渲染一下頁面效果,前后端真正的交互在於這個json數據的請求和返回,而json的本質是 JS 對象的字符串表示法,是字符串,數據格式,以鍵值對呈現[如下圖所示]。后台有一個對象轉化為json的過程,反過來,json傳遞到前端后,應該有一個內容解析/解讀的過程,要知道哪個鍵對應的值是代表什么含義,該怎么處理。最后,關於AJax到底屬於前端還是后端,個人理解是,使用的前端技術,但主要目的是作用於前后端數據交互(請求--獲取--處理的過程),然后到底前后端誰該懂得Ajax的問題,覺得只要想想自己作為前端/后端完全不懂這個的話會不會對自己形成障礙,就有自己的答案了。
小結
應用傳統的web開發模式,成熟的框架逐步在完善,不過絕大部分框架都是針對前端或者后端,前端層出不窮的樣式插件模板,后台不斷更新的數據操作和技術選型,但是針對前后端交互的部分,個人覺得還有很大的提升空間。以Jsp為例,熟悉前端的(全棧?)后台開發人員操作起來會相較方便,雖然他的雜合前后端代碼廣受詬病,但是事實是,Jsp仍然有許多項目是采用的Jsp開發。html + Ajax + js有許多優秀的性質,也還有很多需要完善的地方。目前Ajax應用的已經比較廣泛了,所以項目中往往會有兩種請求混雜的情況(比較直觀就是我們應用Spring MVC時,控制層里的方法,有的加了@Responsebody注解,有的則沒有),可以根據項目的需要決定是否采用。