為什么要前后端分離?
在以前的學習代碼中,可以看出來我們在jsp頁面頁面上也通過EL表達式和jstl寫了很多的java程序,這實際上在前端的頁面中混入了很多后端的邏輯,這就是傳統的web開發。在傳統的web開發中,頁面展示的內容以及頁面之間的跳轉邏輯,全都由后台來控制,這導致了前后端耦合度非常高,耦合度高則意味着,擴展性差,維護性差,等等問題
傳統開發的問題如下:
- 耦合度高
- 調試麻煩,出現問題時往往需要前后台一起檢查
- 開發效率低,前后端相互依賴,溝通成本,維護成本高
- 擴展性差,無法兼容其他終端
- 交互邏輯混亂(還記得分頁顯示嗎),最終造成代碼腐爛
上述問題產生的根本原因在於前后端沒有明顯的分界,嚴重耦合在一起,想要解決這些問題的核心也就是將前后端代碼完全分開,所以我們需要利用我們的json和ajax來實現前后端的分離,也就是后端僅僅需要為前端以json形式來提供數據接口即可,這樣在一定程度上可以減輕后端壓力。簡單說也就是MVC中后端僅僅負責M和service即可,頁面的渲染和跳轉邏輯由前端來做。
簡單的說:
前后端分離在傳統開發上增加了一個服務器處理靜態資源,將View層和Controller層放到了前端,后台僅需處理數據存取相關以及業務邏輯相關
前端:負責View和Controller層。
后端:只負責Model層,業務處理/數據等。
前后端分離的優缺點
優點:
- 關注點分離,視圖層和控制層邏輯移到了前端,后端更注重業務邏輯和系統構架
- 耦合大大降低,開發效率和維護效率都得到提高
- 錯誤友好,后台錯誤不影響前台界面展示
- 對於開發者,前后端不再需要過多的涉及彼此的開發語言
缺點:
-
前端開發者壓力更大,需要關注Controller層
-
增加靜態服務器后,系統結構更復雜
-
更多的HTTP請求,在移動端運行效率差
-
邏輯靠近前端,不同平台需針對性重復實現,(安卓iOS+web)
-
SEO優化無力,爬蟲大多不支持ajax
前后端分離后的流程
Controller層中會使用流程控制來完成數據校驗,數據解析,頁面的跳轉等動作,那么如何完成呢,這就需要使用到JavaScript了
那么一個前后端分離的項目,前端是如何完成最終的數據展示呢?
可以看到,這里想要獲得一個完整的頁面,我們需要訪問兩次服務器。但是這樣也有好處,比如如果前端是其他的例如iOS,安卓,則無需請求靜態頁面,頁面的繪制是由系統原始語言實現的,只需要向后台請求json數據即可。這樣提高了后台數據的可重用性。
為什么我們需要JSON?
因為前后端分離后,我們就不能使用EL表達式來獲取request域中的數據了,因為頁面不在由tomcat服務器來部署,所以我們需要一種數據結構來發送給前端。
JSON全稱(JavaScript Object Notation),js對象表示法,是一種輕量級數據交換格式,你可以將其看做Map數據結構,以鍵值對形式存儲
為什么我們需要Ajax?
Ajax是客戶端的一種請求方式,全稱(Asynchronous Javascript And XML)
用於異步的向服務器發送HTTP請求並獲取響應數據,異步的好處在於,請求期間瀏覽器不會卡死,可以正常響應用戶操作;而常見的表單提交,和直接打開指定地址,都是同步的;
json和對象Bean相互轉換
好啦,整理清楚思路后,我們來簡單的看一下json和Ajax是如何使用的吧。
這里使用了阿里巴巴的fastjson。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class JSONTest {
public static void main(String[] args) {
UserBean bean = new UserBean();
bean.name = "Jeason";
bean.sex = "man";
String s = JSON.toJSONString(bean);
System.out.println(s);
List<UserBean> list = new ArrayList<>();
list.add( bean);
list.add( new UserBean("Tom","man"));
String s1 = JSON.toJSONString(list);
System.out.println(s1);
String json = "{\"name\":\"Jeason\",\"sex\":\"man\"}";
UserBean bean1 = JSON.parseObject(json, UserBean.class);
System.out.println(bean1);
JSONObject jsonObject = new JSONObject();
jsonObject.put("data",bean);
System.out.println(jsonObject);
}
}
輸出如下:
{"name":"Jeason","sex":"man"}
[{"name":"Jeason","sex":"man"},{"name":"Tom","sex":"man"}]
UserBean{name='Jeason', sex='man'}
{"data":{"name":"Jeason","sex":"man"}}
使用Ajax進行異步請求
先構建一個Servlet程序,使用json來傳遞數據
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "JSONServlet" ,urlPatterns = "/testJSON")
public class JSONServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//告訴客戶端返回值的類型是JSON
response.setContentType("application/json");
//設置同源
response.setHeader("Access-Control-Allow-Origin","*");
response.getWriter().println("{\"name\":\"Jeason\",\"sex\":\"man\"}");
}
}
然后我們在頁面中使用Ajax來展示收到的數據
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
</head>
<body>
<h1>這是主頁</h1>
<script>
//發送一個異步請求
$.ajax({
url:"http://localhost:8080/day34_2/testJSON",
success:function(data){
console.log(data);
document.body.insertAdjacentHTML("beforeend","<h1>%</h1>".replace("%",data.name));
document.body.insertAdjacentHTML("beforeend","<h1>%</h1>".replace("%",data.sex));
document.getElementById("img").src = "";
},
error:function(err){
console.log(err);
document.getElementById("img").src = "";
}
});
</script>
</body>
</html>
注意這里我們要引入query
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>