閱讀620 返回首頁    go 技術社區[雲棲]


《Servlet、JSP和Spring MVC初學指南》——第2章 會話管理 2.1URL重寫

本節書摘來自異步社區《Servlet、JSP和Spring MVC初學指南》一書中的第2章,第2.1節,作者:【加】Budi Kurniawan(克尼亞萬) , 【美】Paul Deck著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看

第2章 會話管理

由於HTTP的無狀態性,使得會話管理或會話跟蹤成為Web應用開發一個無可避免的主題。默認下,一個Web服務器無法區分一個HTTP請求是否為第一次訪問。

例如,一個Web郵件應用要求用戶登錄後才能查看郵件,因此,當用戶輸入了相應的用戶名和密碼後,應用不應該再次提示需要用戶登錄,應用必須記住哪些用戶已經登錄。換句話說,應用必須能管理用戶的會話。

本章將闡述4種不同的狀態保持技術:URL重寫、隱藏域、cookies和HTTPSession對象。本章的示例代碼為app02a。

2.1 URL重寫

URL重寫是一種會話跟蹤技術,它將一個或多個token添加到URL的查詢字符串中,每個token通常為key=value形式,如下:

url?key-1=value-1&key-2=value-2 ... &key-n=value-n
注意,URL和tokens間用問號(?)分割,token間用與號(&)。

URL重寫適合於tokens無須在太多URL間傳遞的情況下,然而它有如下限製:

URL在某些瀏覽器上最大長度為2000字符;
若要傳遞值到下一個資源,需要將值插入到鏈接中,換句話說,靜態頁麵很難傳值;
URL重寫需要在服務端上完成,所有的鏈接都必須帶值,因此當一個頁麵存在很多鏈接時,處理過程會是一個不小的挑戰;
某些字符,例如空格、與和問號等必須用base64編碼;
所有的信息都是可見的,某些情況下不合適。
因為存在如上限製,URL重寫僅適合於信息僅在少量頁麵間傳遞,且信息本身不敏感。

清單2.1中的Top10Servlet類會顯示最受遊客青睞的10個倫敦和巴黎的景點。信息分成兩頁展示,第一頁展示指定城市的5個景點,第二頁展示另外5個。該Servlet使用URL重寫來記錄所選擇的城市和頁數。該類擴展自HttpServlet,並通過/top10訪問。

清單2.1 Top10Servlet類

package app02a.urlrewriting;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Top10Servlet", urlPatterns = { "/top10" })
public class Top10Servlet extends HttpServlet {
    private static final long serialVersionUID = 987654321L;

    private List<String> londonAttractions;
    private List<String> parisAttractions;

    @Override
    public void init() throws ServletException {
        londonAttractions = new ArrayList<String>(10);
        londonAttractions.add("Buckingham Palace");
        londonAttractions.add("London Eye");
        londonAttractions.add("British Museum");
        londonAttractions.add("National Gallery");
        londonAttractions.add("Big Ben");
        londonAttractions.add("Tower of London");
        londonAttractions.add("Natural History Museum");
        londonAttractions.add("Canary Wharf");
        londonAttractions.add("2012 Olympic Park");
        londonAttractions.add("St Paul's Cathedral");

        parisAttractions = new ArrayList<String>(10);
        parisAttractions.add("Eiffel Tower");
        parisAttractions.add("Notre Dame");
        parisAttractions.add("The Louvre");
        parisAttractions.add("Champs Elysees");
        parisAttractions.add("Arc de Triomphe");
        parisAttractions.add("Sainte Chapelle Church");
        parisAttractions.add("Les Invalides");
        parisAttractions.add("Musee d'Orsay");
        parisAttractions.add("Montmarte");
        parisAttractions.add("Sacre Couer Basilica");
    }

    @Override
    public void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {
        String city = request.getParameter("city");
        if (city != null &&
                (city.equals("london") || city.equals("paris"))) {
            // show attractions
            showAttractions(request, response, city);
        } else {
            // show main page
            showMainPage(request, response);
        }
    }

    private void showMainPage(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.print("<html><head>" +
                "<title>Top 10 Tourist Attractions</title>" +
                "</head><body>" +
                "Please select a city:" +
                "<br/><a href='?city=london'>London</a>" +
                "<br/><a href='?city=paris'>Paris</a>" +
                "</body></html>");
    }

    private void showAttractions(HttpServletRequest request,
            HttpServletResponse response, String city)
            throws ServletException, IOException {

        int page = 1;
        String pageParameter = request.getParameter("page");
        if (pageParameter != null) {
            try {
                page = Integer.parseInt(pageParameter);
            } catch (NumberFormatException e) {
                // do nothing and retain default value for page
            }
            if (page > 2) {
                page = 1;
            }            
        }
        List<String> attractions = null;
        if (city.equals("london")) {
            attractions = londonAttractions;
        } else if (city.equals("paris")) {
            attractions = parisAttractions;
        }
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.println("<html><head>" +
                "<title>Top 10 Tourist Attractions</title>" +
                "</head><body>");
        writer.println("<a href='top10'>Select City</a> ");
        writer.println("<hr/>Page " + page + "<hr/>");
        int start = page * 5 - 5;
        for (int i = start; i < start + 5; i++) {
            writer.println(attractions.get(i) + "<br/>");
        }
        writer.print("<hr style='color:blue'/>" +
                "<a href='?city=" + city +
                "&page=1'>Page 1</a>");
        writer.println("&nbsp; <a href='?city=" + city +
                "&page=2'>Page 2</a>");
        writer.println("</body></html>");
    }
}

init方法,僅當該servlet第一次被用戶訪問時調用,構造兩個類級別的列表,londonAttractions和parisAttractions,每個列表有10個景點。

doGet方法,該方法每次請求時被調用,檢查URL中是否包括請求參數city,並且其值是否為“london”或“paris”,方法據此決定是調用showAttractions方法還是showMainPage方法:

String city = request.getParameter("city");
        if (city != null &&
                (city.equals("london") || city.equals("paris"))) {
            // show attractions
            showAttractions(request, response, city);
        } else {
            // show main page
            showMainPage(request, response);
        }

用戶一開始訪問該servlet時不帶任何請求參數,此時調用showMainPage,該方法發送兩個鏈接到瀏覽器,每個鏈接都包含token:city=cityName。用戶所見如圖2.1所示,現在用戶可以選擇一個城市。

screenshot

圖2.1 Top10Servlet的初始頁麵

如果你查看網頁源代碼,你會看見如下HTML:

Please select a city:<br/>
<a href='?city=london'>London</a><br/>
<a href='?city=paris'>Paris</a>

請注意a元素中的href屬性,該屬性值包括一個問號加token city=london或city=paris. 注意,此處為相對URL,即URL中沒有協議部分,相對於當前頁麵。因此,若你點擊了任一鏈接,則會提交

https://localhost:8080/app02a/top10?city=london

https://localhost:8080/app02a/top10?city=paris
到服務器上。

根據用戶所點擊的鏈接,doGet方法識別請求參數的city值並傳遞給showAttractions方法,該方法會檢查URL中是否包含page參數,如果沒有該參數或該參數值無法轉換為數字,則該方法設定page參數值為1,並將頭5個景點發給客戶端。圖2.2為選擇倫敦時的界麵。

showAttractions方法還發送了3個鏈接到客戶端:Select City、Page 1和Page 2。Select City 是無參數訪問servlet,Page 1和Page 2鏈接包括兩個tokens,即city和page:

https://localhost:8080/app02a/top10?city=cityName&page=pageNumber
若選擇了倫敦,並點擊了Page 2,則將以下URL發送給服務端:

https://localhost:8080/app02a/top10?city=london&page=2

screenshot

圖2.2 倫敦前十景點,第一頁

此時係統會展示倫敦的另外5個景點,如圖2.3所示。

screenshot

圖2.3 倫敦前十景點,第二頁

本例展示了如何用URL重寫技術來傳遞參數——city到服務端以便服務端能正確展示。

最後更新:2017-05-27 18:01:26

  上一篇:go  《Servlet、JSP和Spring MVC初學指南》——2.2 隱藏域
  下一篇:go  《Servlet、JSP和Spring MVC初學指南》——1.12 小結