day19-web開發會話技術01

来源:https://www.cnblogs.com/liyuelian/archive/2022/11/20/16909879.html
-Advertisement-
Play Games

WEB開發會話技術01 1.會話 Web開發中,用到的4種會話跟蹤技術 - 博客園 (cnblogs.com) 會話的基本介紹 什麼是會話? 會話可簡單理解為:用戶開一個瀏覽器,點擊多個超鏈接,訪問伺服器多個web資源,然後關閉瀏覽器,整個過程稱之為一個會話。 會話過程中要解決的一些問題: (1)每 ...


WEB開發會話技術01

1.會話

Web開發中,用到的4種會話跟蹤技術 - 博客園 (cnblogs.com)

  • 會話的基本介紹
  1. 什麼是會話?

    會話可簡單理解為:用戶開一個瀏覽器,點擊多個超鏈接,訪問伺服器多個web資源,然後關閉瀏覽器,整個過程稱之為一個會話。

  2. 會話過程中要解決的一些問題:

    (1)每個用戶在使用瀏覽器與伺服器進行會話的過程中,不可避免各自會產生一些數據,伺服器要想辦法為 每個用戶保存這些數據

    (2)例如多個用戶點擊超鏈接通過一個servlet各自購買了一個商品,伺服器應該想辦法把每一個用戶購買的 商品保存在各自的地方,以便於這些用戶點結賬servlet時,結賬servlet可以得到用戶各自購買的商品, 為用戶結賬。

  • 會話的兩種技術
  1. Session
  2. Cookie

事實上,Session和Cookie往往連在一起用的

2.Cookie基本介紹和作用

2.1Cookie有什麼用

問題1:大家在訪問一個網站的時候,是否能看到提示你上次登錄網站的時間,要註意的是不同用戶的上次登錄時間肯定是不一樣的,這是怎麼實現的?

問題2:在訪問某個購物網站的時候,是否能看到提示你曾經瀏覽過的商品,不同的用戶瀏覽過的商品肯定是不一樣的,這又是怎麼實現的?

問題3:還有我們登錄某個網站的時候,往往都可以選擇保存登錄信息,不用重覆輸入登錄信息,這又是怎麼做到的?

image-20221120145829111
  • 解決之道-Cookie技術

    Cookie是客戶端技術,伺服器把每個用戶的數據以cookie的形式寫給用戶各自的瀏覽器。當用戶使用瀏覽器再去訪問伺服器中的web資源時,就會帶著各自的數據去。這樣,web資源處理的就是用戶各自的數據了。

  • cookie可以用來做什麼?

    1. 保存上次登錄時間等信息

    2. 保存用戶名,密碼,在一定時間內不用重新登錄

      image-20221120154626672
    3. 網站的個性化,比如定製網站的服務,內容等

2.2Cookie介紹

通俗地說,就是當一個用戶通過HTTP協議訪問一個伺服器的時候,這個伺服器會將一些key/value鍵值對返回給客戶端瀏覽器,並給這些數據加上一些限制條件,在條件符合時這個用戶下次訪問這個伺服器的時候,數據又被完整地帶回給伺服器。

image-20221120153301025
  1. Cookie是伺服器在客戶端保存的用戶的信息,比如登錄名,瀏覽歷史等,就可以以cookie方式存儲

  2. Cookie信息就像是小甜餅一樣,數據量並不大,服務端在需要的時候可以從客戶端/瀏覽器讀取(HTTP協議)

    例如:如果請求的是某網站,就會到瀏覽器存儲的cookie裡面找該網站對應的cookie,然後通過http請求頭的Cookie欄位,將其發送給對應的網站伺服器

  3. 再次說明,cookie數據是保存在瀏覽器的

image-20221120153414395

3.Cookie的基本使用

  1. cookie有點像一張表(k-v),分兩列,一個是名字,一個是值,數據類型都是String

    image-20221120155222157
  2. 如果創建一個Cookie(由服務端創建)

    Cookie cookie=new Cookie(String name,String val);
    cookie.setMaxAge();//保存時間
    
  3. 如何將一個Cookie添加到客戶端

    response.addCookie(cookie);
    
  4. 如何讀取cookie(在服務端讀取到cookie信息)

    request.getCookie();
    

4.Cookie底層實現機制

首先創建一個web工程,因為cookie是servlet的一部分,因此要引入servlet-api,然後配置Tomcat

image-20221120162605752

4.1創建cookie

例子

在web項目中創建並配置servlet:

web.xml:

<servlet>
    <servlet-name>CreatCookie</servlet-name>
    <servlet-class>com.li.cookie.CreatCookie</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>CreatCookie</servlet-name>
    <url-pattern>/creatCookie</url-pattern>
</servlet-mapping>

CreatCookie:

package com.li.cookie;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 演示如何創建cookie並保存到瀏覽器
 */
public class CreatCookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CreatCookie doPost被調用");
        //1.創建一個Cookie對象
        //name-value形式,其中name是唯一不可重覆的;value是cookie的值
        //可以創建多個cookie對象
        //這時cookie還在伺服器端
        Cookie cookie = new Cookie("username", "olien");

        response.setContentType("text/html;charset=utf-8");

        //2.將cookie發送給瀏覽器,讓瀏覽器將該cookie保存起來
        response.addCookie(cookie);

        PrintWriter writer = response.getWriter();
        writer.print("<h1>創建cookie成功</h1>");
        writer.flush();
        writer.close();
    }
}
  1. 運行tomcat,在瀏覽器訪問該servlet資源:

    image-20221120164436796
  2. 打開瀏覽器控制台,可以在HTTP響應中看到伺服器發送的cookie:

    image-20221120164702228
  3. 在控制台存儲處也可以看到該cookie:

    image-20221120175216621

4.2讀取cookie

如果瀏覽器保存了某一個網站的cookie信息後,當它發送請求給網站伺服器時,會自動地帶上跟這個伺服器關聯的cookie

例子

web.xml:

<servlet>
    <servlet-name>ReadCookies</servlet-name>
    <servlet-class>com.li.cookie.ReadCookies</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ReadCookies</servlet-name>
    <url-pattern>/readCookies</url-pattern>
</servlet-mapping>

ReadCookies:

package com.li.cookie;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 讀取瀏覽器發來的cookie信息[基於http協議]
 */
public class ReadCookies extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("ReadCookies doPost被調用");
        //1.通過request對象讀取cookie信息
        Cookie[] cookies = request.getCookies();
        //2.遍歷一下cookie
        if (cookies != null && cookies.length != 0) {
            for (Cookie cookie : cookies) {
                System.out.println("cookie name= " + cookie.getName()
                        + " value= " + cookie.getValue());
            }
        }
        //3.給瀏覽器返回信息
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>讀取cookie信息成功</h1>");
        writer.flush();
        writer.close();
    }
}
  1. redeployTomcat,在瀏覽器訪問該servlet,輸出如下:

    image-20221120170952097
  2. 使用瀏覽器抓包,可以看到瀏覽器發送的http請求中帶有和當前伺服器關聯的cookie:

    image-20221120175032093
  3. 伺服器後臺輸出:

    image-20221120174838307

4.3JSESSIONID說明

有如下的情況:

A瀏覽器和其他瀏覽器都發送了請求給伺服器,伺服器分別創建了不同的cookie給這些瀏覽器,要求它們進行保存。當A瀏覽器帶上cookie信息發送給伺服器的時候,伺服器怎麼在許多會話中區分這次會話是跟A瀏覽器關聯的,還是跟其他不同的瀏覽器關聯的呢?

答案是用 jsessionid。不同的會話,jsessionid不同

驗證:不同的會話,jsessionid不同

  1. 第一次訪問Tomcat首頁: JSESSIONID=7F9AC09830943EEB6C58285812E5DE1C

    image-20221120181834381
  2. 關閉瀏覽器後重新打開再訪問:JSESSIONID=1231B81D45B63812FCF682FD5761AA30

    image-20221120182825209

如果重新打開瀏覽器發現jsession還是同一個,可能是瀏覽器緩存問題

5.Cookie應用實例

5.1讀取指定的cookie

需求:在伺服器端如何讀取到指定的cookie

(1)給定cookie的name,返回該cookie的值

(2)如果不存在該cookie,則返回null

例子

web.xml:

<servlet>
    <servlet-name>ReadCookieByNameServlet</servlet-name>
    <servlet-class>com.li.cookie.ReadCookieByNameServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ReadCookieByNameServlet</servlet-name>
    <url-pattern>/readCookieByName</url-pattern>
</servlet-mapping>

修改CreatCookie:

package com.li.cookie;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 演示如何創建cookie並保存到瀏覽器
 */
public class CreatCookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CreatCookie doPost被調用");
        //1.創建一個Cookie對象
        //name-value形式,其中name是唯一不可重覆的;value是cookie的值
        //可以創建多個cookie對象
        //這時cookie還在伺服器端
        Cookie cookie = new Cookie("username", "jack");
        Cookie cookie2 = new Cookie("email", "[email protected]");

        response.setContentType("text/html;charset=utf-8");

        //2.將cookie發送給瀏覽器,讓瀏覽器將該cookie保存起來
        response.addCookie(cookie);
        response.addCookie(cookie2);

        PrintWriter writer = response.getWriter();
        writer.print("<h1>創建cookie成功</h1>");
        writer.flush();
        writer.close();
    }
}

ReadCookieByNameServlet:

package com.li.cookie;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

public class ReadCookieByNameServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //System.out.println("ReadCookieByNameServlet doPost..");

        //得到指定的cookie的值

        //1.首先得到瀏覽器攜帶的所有cookies
        Cookie[] cookies = request.getCookies();
        //2.使用工具類來獲取指定的cookie
        Cookie emailCookie = CookieUtils.readCookieByName("email", cookies);
        if (null != emailCookie) {
            System.out.println("得到emailCookie name=" + emailCookie.getName()
                    + " value=" + emailCookie.getValue());
        } else {
            System.out.println("沒有這個cookie");
        }

        //3.給瀏覽器返回信息
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>完成讀取cookie的任務..</h1>");
        writer.flush();
        writer.close();
    }
}

工具類CookieUtils:

package com.li.cookie;

import javax.servlet.http.Cookie;

public class CookieUtils {
    //編寫一個方法,返回指定名字的cookie值
    public static Cookie readCookieByName(String name, Cookie[] cookies) {
        //判斷傳入的參數是否正確
        if (name == null || "".equals(name) || cookies == null || cookies.length == 0) {
            return null;
        }
        //否則,就遍歷cookies
        for (Cookie cookie : cookies) {
            if (name.equals(cookie.getName())) {
                return cookie;
            }
        }
        return null;
    }
}
  1. redeployTomcat,在瀏覽器中先訪問creatCookie資源(創建cookie)

    image-20221120185432879
  2. 再訪問readCookieByName資源:

    image-20221120185541335
  3. 伺服器後臺輸出:

    image-20221120185621976

5.2修改cookie

需求:演示如何修改cookie

5.2.1方式一

  1. 先找到需要修改的Cookie對象
  2. 調用setValue()方法賦予其新的Cookie值
  3. 調用response.addCookie()通知客戶端保存修改

例子

(1)給定一個cookie的name,找到該cookie,如果有,則修改該cookie的值為xxx

(2)如果找不到該cookie,則提示沒有該cookie

CookieUtils不變。

UpdateCookie:

package com.li.cookie;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(urlPatterns = {"/updateCookie"})
public class UpdateCookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("updateCookie doPost被調用...");
        /**
         * 需求:演示如何修改cookie
         * (1)給定一個cookie的name,找到該cookie,如果有,則修改該cookie的值為xxx
         * (2)如果找不到該cookie,則提示沒有該cookie
         */
        //1.根據name去查找cookie
        String cookieName = "email";
        Cookie[] cookies = request.getCookies();
        Cookie cookie = CookieUtils.readCookieByName(cookieName, cookies);
        if (cookie == null) {//在該瀏覽器沒有email cookie
            System.out.println("當前訪問服務端的瀏覽器沒有該cookie");
        } else {
            cookie.setValue("[email protected]");
        }

        //2.遍歷一下,看看有沒有變化
        System.out.println("=====修改後的cookie信息=====");
        for (Cookie cookie1 : cookies) {
            System.out.println("cookie name=" + cookie1.getName()
                    + " value=" + cookie1.getValue());
        }

        //3.給瀏覽器返回修改後的cookies
        if (cookie != null) {
            response.addCookie(cookie);
        }

        //4.給瀏覽器返回信息提示
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>完成修改cookie的任務</h1>");
        writer.flush();
        writer.close();
    }
}
  1. 修改前瀏覽器對應的cookie如下:

    image-20221120192550275
  2. redeployTomcat,在瀏覽器訪問updateCookie資源後,cookie的值改變了:

    image-20221120192716171
  3. 伺服器後臺輸出:

    image-20221120192744108

5.2.2方式二

創建一個同名的cookie發送給瀏覽器,相當於覆蓋原來的cookie的值

Cookie cookie = new Cookie("key1","value1");
response.addCookie(cookie);//底層http響應包的set-cookie:xxx相應變化

6.Cookie的生命周期

預設情況下,Cookie只在瀏覽器的記憶體中存活,也就是說,當你關閉瀏覽器後,Cookie就會消失。但是也可以通過方法設置cookie的生存時間。

cookie的生命周期指的是如何管理cookie,什麼時候cookie被銷毀。

  • setMaxAge(int expiry):設置 cookie 的最大生存時間,以秒為單位
    • 整數:表示在指定的秒數後過期
    • 負數:表示瀏覽器關閉,cookie就會被刪除(預設值是-1)
    • 0,表示馬上刪除cookie

例子1:指定參數為整數

CookieLive:

package com.li.cookie;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(urlPatterns = {"/CookieLive"})
public class CookieLive extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CookieLive doPost被調用...");
        //創建一個cookie,生命周期為 60s
        Cookie cookie = new Cookie("job", "java");
        //1.從創建改cookie開始計時,60秒後就無效
        //2.由瀏覽器來根據創建的時間來開始計時,到時間後就認為該cookie無效
        //3.如果該cookie無效了,那麼瀏覽器在發出HTTP請求時,就不會帶上該cookie
        cookie.setMaxAge(60);

        //將cookie保存到瀏覽器
        response.addCookie(cookie);

        //給瀏覽器返回信息
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>設置cookie生命周期成功</h1>");
        writer.flush();
        writer.close();
    }
}
  1. 在瀏覽器中訪問該servlet:

    image-20221120221656177

  2. 可以看到該cookie的創建時間是 "Sun, 20 Nov 2022 14:15:39 GMT"

    真實時間為上述時間再加八小時

    image-20221120221755132
  3. 超過60s後,再去訪問Tomcat伺服器:

    代碼見4.2

    image-20221120222222568

    在瀏覽器發送的HTTP請求中的Cookie欄位已經沒有了設置的cookie:

說明:由瀏覽器來根據創建的時間來開始計時,到時間後就認為該cookie無效。如果該cookie無效了,那麼瀏覽器在發出HTTP請求時,就不會帶上該cookie。

但是此時cookie沒有被刪除,在關閉瀏覽器的時候才會被刪除。

例子2:演示刪除cookie

刪除下圖名為email的cookie

image-20221120223510257
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.虛擬機下載 官網下載地址:https://www.kali.org/get-kali/#kali-virtual-machines 選擇VMware版本下載,並解壓 2.打開虛擬機 選擇打開虛擬機,瀏覽到剛纔壓縮包解壓路徑,選擇.vmx文件打開 開啟此虛擬機 用戶名密碼都是kali 3.設置ro ...
  • 世界上的開源許可證(Open Source License)大概有上百種,而我們常用的開源軟體協議大致有GPL、BSD、MIT、Mozilla、Apache和LGPL。 從下圖中可以看出幾種開源軟體協議的區別。 以下是上述協議的簡單介紹: GPL GNU是GNU General Public Lic ...
  • GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 GreatSQL是MySQL的國產分支版本,使用上與MySQL一致。 作者: 如常 Debezium Incremental snapshotting Introduction CDC(Change-Data-Captur ...
  • 資料庫面試測試題(一) 簡述當前主流RDBMS軟體有哪些?開源且跨平臺的資料庫軟體有哪些? 參考答案 當前主流的資料庫伺服器軟體有: Oracle 、 DB2 、 SQL SERVER 、MySQL 等 ,其中只有MySQL是既開源又跨平臺的資料庫服務軟體。 簡述MySQL資料庫的服務進程名、預設端 ...
  • 1、文本類指令 {{}}、v-text 都是用於綁定節點的文本; 二者區別:{{}}這種綁定值的方式在頁面會出現“{{}}”一閃而過的效果 解決{{}}在頁面出現一閃而過的辦法: // css: [v-cloak] { display: 'none' }// html <h1 v-cloak>{{m ...
  • 5.10 介面開發-分片上傳 第2-1-2章 傳統方式安裝FastDFS-附FastDFS常用命令 第2-1-3章 docker-compose安裝FastDFS,實現文件存儲服務 第2-1-5章 docker安裝MinIO實現文件存儲服務-springboot整合minio-minio全網最全的資 ...
  • static_assert是c++11添加的新語法,它可以使我們在編譯期間檢測一些斷言條件是否為真,如果不滿足條件將會產生一條編譯錯誤信息。 使用靜態斷言可以提前暴露許多問題到編譯階段,極大的方便了我們對代碼的排錯,提前將一些bug扼殺在搖籃里。 然而有時候靜態斷言並不能如我們預期的那樣工作,今天就 ...
  • # 1.函數的作用域 # 全局變數的作用域: # 一般在函數體外定義的變數成為全局變數,在函數內部定義的變數稱為局部變數。 # 全局變數所有作用域都可用,局部變數只能在本函數可用,變 # 量的使用順序是,局部變數 > 全局變數, 也就是說:優先使用局部變數 # # global關鍵字: # 為瞭解決 ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...